home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 October / Macworld (1998-10).dmg / Shareware World / Info / For Developers / MacZoop 1.8.4 / More Classes / Window Classes / ZDialog.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-16  |  77.0 KB  |  2,993 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZDialog.cpp            -- a dialog box
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZDialog.h"
  23. #include    "MacZoop.h"
  24. #include    "ZGrafState.h"
  25.  
  26. #include    <dialogs.h>
  27. #include    <palettes.h>
  28. #include    <fp.h>
  29.  
  30. // static method and global UPP to handle user items in dialogs in a general
  31. // object-oriented fashion. Hey- cool feature!
  32.  
  33. static pascal void    UserItemVectorProc(DialogPtr theDialog, short item);
  34. UserItemUPP    gUIVectorUPP = NewUserItemProc(UserItemVectorProc);
  35.  
  36.  
  37. CLASSCONSTRUCTOR( ZDialog );
  38.  
  39. /*-------------------------------***  CONSTRUCTOR  ***----------------------------------*/
  40.  
  41.  
  42. ZDialog::ZDialog( ZCommander* aBoss, const short dialogID )
  43.     : ZWindow( aBoss, dialogID )
  44. {
  45.     classID = CLASS_ZDialog;
  46.     
  47.     isModal = FALSE;    // set up by MakeMacWindow
  48.     isInline = FALSE;    // set up by RunModal.
  49.     dItemInfo = NULL;
  50.     ictb = NULL;
  51.     signalDismiss = 0;
  52.     exitItem = 0;
  53.     baseItems = 0;
  54. }
  55.  
  56.  
  57. ZDialog::ZDialog()
  58.     : ZWindow()
  59. {
  60.     classID = CLASS_ZDialog;
  61.     
  62.     isModal = FALSE;    // set up by MakeMacWindow
  63.     isInline = FALSE;    // set up by RunModal.
  64.     dItemInfo = NULL;
  65.     ictb = NULL;
  66.     signalDismiss = 0;
  67.     exitItem = 0;
  68.     baseItems = 0;
  69. }
  70.  
  71.  
  72. /*---------------------------------***  DESTRUCTOR  ***----------------------------------*/
  73.  
  74.  
  75. ZDialog::~ZDialog()
  76. {
  77.     if ( dItemInfo )
  78.     {
  79.         // make sure any allocated mirror TERecords are disposed of:
  80.         
  81.         short             i = CountDITL( macWindow );
  82.         unsigned short    flags;
  83.         TEHandle        th;
  84.         long            max;
  85.         
  86.         while( i )
  87.         {
  88.             GetEditFieldInfo( i--, &flags, (long*) &th, &max );
  89.         
  90.             if (( flags & editFieldHCMirrorAlloc ) && ( th != NULL ))
  91.                 TEDispose( th );
  92.         }
  93.         
  94.         DisposeHandle((Handle) dItemInfo );
  95.     }
  96.     
  97.     if ( ictb )
  98.         DisposeHandle((Handle) ictb );
  99.  
  100.     if ( macWindow )
  101.     {
  102.         // save off position in prefs if this feature enabled. No point doing it if the
  103.         // dialog is not a moveable type:
  104.         
  105.     #if _AUTO_WPOS_FOR_DIALOGS
  106.         
  107.         short wVar = GetWVariant( macWindow );
  108.         
  109.         if ( !isModal || wVar == movableDBoxProc )
  110.             SavePosition();
  111.         
  112.     #endif
  113.         
  114.         if ( MacHasDM())
  115.             RemoveDragHandlers();
  116.  
  117.         DisposeDialog( macWindow );
  118.     }
  119.     
  120.     macWindow = NULL;
  121. }
  122.  
  123. /*-------------------------------***  INITZWINDOW  ***----------------------------------*/
  124. /*    
  125.  
  126. construct the dialog and set it up
  127.  
  128. ----------------------------------------------------------------------------------------*/
  129.  
  130. void    ZDialog::InitZWindow()
  131. {
  132.     MakeMacWindow( windID );    // make the dialog box, and set modal flag
  133.  
  134.     if ( MacHasDM())
  135.         InstallDragHandlers();
  136.  
  137.     short    item = baseItems = CountDITL( macWindow );
  138.  
  139.     // set up the handle which is a list of DItemInfo records (1 for every dialog item)
  140.     
  141.     FailNIL( dItemInfo = ( DItemInfoHdl ) NewHandleClear( sizeof( DItemInfo ) * item ));
  142.  
  143.     SetUpUserItems();            // install user item procs so we get callbacks
  144.     SetUpRadioGroups();            // automatically deal with radio button groups
  145.     Focus();                    // make sure dialog is focussed for setup call
  146.     SetUp();                    // call user's set up method
  147.     OutlineDefaultItem();        // set default button to ok button
  148.     DisableItem( 0 );            // initially disable everything- will be reset correctly by
  149.                                 // initial activate event
  150.     
  151.     // tell the window manager of our existence. This must be done after the
  152.     // full build of the mac window since the window manager needs to get
  153.     // information from it. Thus if you override this method, make sure you
  154.     // make the same call.
  155.     
  156.     gWindowManager->AddWindow( this );
  157.     ResetAlertStage();
  158.     
  159.     // restore position if this feature enabled:
  160.     // n.b. does nothing at all if no stored position or no file available, so safe to call
  161.     // regardless.
  162.     
  163.     #if _AUTO_WPOS_FOR_DIALOGS
  164.     RestorePosition();
  165.     #endif
  166. }
  167.  
  168.  
  169. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  170. /*    
  171.  
  172. make a dialog. This tries to construct a dialog using a 'DLOG' resource with the ID
  173. passed. The refcon is set to this object, so do not use it. Sets the modal flag too.
  174.  
  175. ----------------------------------------------------------------------------------------*/
  176.  
  177. void    ZDialog::MakeMacWindow( const short dialogID )
  178. {
  179.     // create the macintosh dialog:
  180.         
  181.     FailNILRes( macWindow = GetNewDialog( dialogID, NULL, (WindowPtr) -1L ));
  182.     
  183.     // set our refcon to point to the object. DO NOT USE THE REFCON!
  184.     
  185.     SetWRefCon( macWindow, (long) this );
  186.     
  187.     // see whether this is modal or not by examining the style of the window. This
  188.     // flag affects the way commands are processed.
  189.     
  190.     short wVar = GetWVariant( macWindow );
  191.     
  192.     isModal = ( wVar == dBoxProc     ||
  193.                 wVar == plainDBox     ||
  194.                 wVar == altDBoxProc ||
  195.                 wVar == movableDBoxProc );
  196.     
  197.     // note that dialogs should normally not set the <isFloating> member, since the window
  198.     // manager knows that dialogs should go in front of floaters anyway. If you use a dialog as
  199.     // a floating window, note that it won't get the menubar and keyboard focus, so you should
  200.     // avoid the use of editable text fields, etc. Though no-one's enforcing any of this, it
  201.     // is bad human interface to have type-in fields in floating windows.
  202.     
  203.     // look for any associated 'ictb' resource and keep a local copy. If not a colour dialog,
  204.     // don't bother with this since only colour dialogs support this feature.
  205.     
  206.     if ( IsColourPort( macWindow ))
  207.     {
  208.         ictb = ( ictbHandle ) GetResource( 'ictb', dialogID );
  209.         
  210.         if ( ictb )
  211.         {
  212.             DetachResource((Handle) ictb );
  213.             HNoPurge((Handle) ictb );
  214.         }
  215.     }
  216. }
  217.  
  218.  
  219. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  220.  
  221.  
  222. void    ZDialog::MakeMacWindow( Rect* aRect, Str255 title, Boolean visible, short varCode, Boolean hasCloseBox, void* userData )
  223. {
  224.     if ( gMacInfo.supportsColour )
  225.         FailNIL( macWindow = NewColorDialog( NULL, aRect, title, visible, varCode, (WindowPtr) -1L, hasCloseBox, 0, (Handle) userData ));
  226.     else
  227.         FailNIL( macWindow = NewDialog( NULL, aRect, title, visible, varCode, (WindowPtr) -1L, hasCloseBox, 0, (Handle) userData ));
  228.  
  229.     SetWRefCon( macWindow, (long) this );
  230.     CopyPString( title, macFile.name );
  231.  
  232.     isModal = ( varCode == dBoxProc     ||
  233.                 varCode == plainDBox     ||
  234.                 varCode == altDBoxProc  ||
  235.                 varCode == movableDBoxProc );
  236. }
  237.  
  238.  
  239. /*-----------------------------***  SETUPUSERITEMS  ***---------------------------------*/
  240. /*    
  241.  
  242. make every user item point to our vector proc for handling these items. Then you can
  243. simply override DrawUserItem to draw anything you want in the dialog!
  244. ----------------------------------------------------------------------------------------*/
  245.  
  246. void    ZDialog::SetUpUserItems( short fromItemNo )
  247. {
  248.     short    item, itemType;
  249.     Handle    itemHand;
  250.     Rect    itemBox;
  251.     
  252.     item = CountDITL( macWindow );
  253.     
  254.     while( item > fromItemNo )
  255.     {
  256.         GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  257.         
  258.         if (( itemType & 0x7F ) == userItem )
  259.             SetDialogItem( macWindow, item, itemType, (Handle) gUIVectorUPP, &itemBox );
  260.             
  261.         item--;
  262.     }
  263. }
  264.  
  265.  
  266.  
  267. /*-----------------------------------***  DRAW  ***-------------------------------------*/
  268. /*    
  269. draws the dialog items
  270. ----------------------------------------------------------------------------------------*/
  271.  
  272. void    ZDialog::Draw()
  273. {
  274.     SetDefaultColours();
  275.     UpdateDialog( macWindow, macWindow->visRgn );
  276.     
  277.     // we also need to correctly draw any disabled edit fields which require that
  278.     // the local DrawUserItem code is called to correctly maintain the disabled appearance.
  279.     
  280.     unsigned short    iFlags;
  281.     short            i = CountDITL( macWindow );
  282.     short            iType;
  283.     
  284.     while ( i )
  285.     {
  286.         iType = GetItemType( i ) & 0x7F;
  287.         
  288.         if ( iType == statText )
  289.         {
  290.             GetEditFieldInfo( i, &iFlags );
  291.         
  292.             if ( iFlags & editFieldIsDisabled )
  293.                 ZDialog::DrawUserItem( i );
  294.         }
  295.         i--;
  296.     }
  297.  
  298.     #ifdef _GREYSCALE_APPEARANCE
  299.     AddGreyscaleEffects();
  300.     #endif    
  301.     
  302.     OutlineDefaultItem();
  303. }
  304.  
  305.  
  306. /*-------------------------------***  DRAWONEITEM  ***----------------------------------*/
  307. /*    
  308. redraws a single item immediately. Call if something needs a quick update in the dialog.
  309. ----------------------------------------------------------------------------------------*/
  310.  
  311. void    ZDialog::DrawOneItem( const short item )
  312. {
  313.     ZGrafState    gs;
  314.     Rect        iBox;
  315.     RgnHandle    udRgn;
  316.     
  317.     Focus();
  318.     GetItemBounds( item, &iBox );
  319.     udRgn = NewRgn();
  320.     RectRgn( udRgn, &iBox );
  321.     
  322.     UpdateDialog( macWindow, udRgn );
  323.     SetClip( udRgn );
  324.     DisposeRgn( udRgn );
  325.     
  326.     #ifdef _GREYSCALE_APPEARANCE
  327.     AddGreyscaleEffects();
  328.     #endif    
  329. }
  330.  
  331.  
  332. /*-----------------------------***  SETDIALOGBASEFONT  ***------------------------------*/
  333. /*    
  334. sets the default font for the dialog if 12 point chicago is not your bag. This affects
  335. only static and editable text items. This changes all such items in the dialog- if
  336. you need to set it on an individual item basis, use the 'ictb' mechanism. Call this once
  337. after InitZWindow(), but before dialog is selected.
  338. ----------------------------------------------------------------------------------------*/
  339.  
  340. void    ZDialog::SetDialogBaseFont( short fontID, short fontSize, short fontStyle )
  341. {
  342.     Focus();
  343.     TextFont( fontID );
  344.     TextFace( fontStyle );
  345.     TextSize( fontSize );
  346.     
  347.     // set the same parameters in the textEdit record
  348.     
  349.     DialogPeek    dp = (DialogPeek) macWindow;
  350.     
  351.     if ( dp->textH )
  352.     {
  353.         (*dp->textH)->txFont = fontID;
  354.         (*dp->textH)->txFace = fontStyle;
  355.         (*dp->textH)->txSize = fontSize;
  356.     
  357.         FontInfo    fi;
  358.         
  359.         GetFontInfo( &fi );
  360.         
  361.         (*dp->textH)->fontAscent = fi.ascent;
  362.         (*dp->textH)->lineHeight = fi.ascent + fi.descent + fi.leading;
  363.         
  364.         TECalText( dp->textH );
  365.     }
  366. }
  367.  
  368.  
  369. /*-----------------------------------***  CLICK  ***------------------------------------*/
  370. /*    
  371. handle clicks in the dialog, This determines the item and calls ClickItem.
  372. ----------------------------------------------------------------------------------------*/
  373.  
  374. void    ZDialog::Click( const Point mouse, const short modifiers )
  375. {
  376.     DialogPeek    dp = ( DialogPeek ) macWindow;
  377.     
  378.     // which item was hit?
  379.     
  380.     short    item = FindDialogItem( macWindow, mouse ) + 1;
  381.     
  382.     // if the item is enabled, call TrackControl, TEClick, etc as needed.
  383.     
  384.     if ( item > 0 )
  385.     {
  386.         short    iType, partCode;
  387.         Handle    iHand;
  388.         Rect    iBox;
  389.         
  390.         GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  391.         
  392.         // if the item is a control, track it. Call ClickItem if control clicked and
  393.         // item was enabled and not unhilited.
  394.         
  395.         if (iType & ctrlItem )
  396.         {
  397.             if ((*(ControlHandle) iHand )->contrlHilite != 255 )
  398.             {
  399.                 partCode = TrackControl((ControlHandle) iHand, mouse, ( ControlActionUPP ) -1L );
  400.             
  401.                 if (( partCode != 0 ) && (( iType & 0x80 ) == 0 ))
  402.                 {
  403.                     // if a button, set the local zoom source rect
  404.                     
  405.                     if ( iType == ( btnCtrl + ctrlItem ))
  406.                     {
  407.                         GrafPtr        savePort;
  408.                         
  409.                         GetPort( &savePort );
  410.                         SetPort( macWindow );
  411.                         
  412.                         SetLocalZoomSource( &iBox );
  413.                         
  414.                         SetPort( savePort );
  415.                     }
  416.  
  417.                     ClickItem( item );
  418.                 }
  419.             }
  420.         }
  421.         else
  422.         {
  423.             if ( iType & editText )
  424.             {
  425.                 // if an edit field, pass click to text edit. If not in the current
  426.                 // field, switch fields to the one clicked.
  427.                 
  428.                 ZGrafState    zg;
  429.                 
  430.                 if ( item != dp->editField + 1)
  431.                     SelectItem (item );
  432.  
  433.                 SetTEItemDataFromIctb( item, TRUE );
  434.                 TEClick( mouse, (modifiers & shiftKey) == shiftKey , dp->textH );
  435.             }
  436.             
  437.             // all enabled items are passed to ClickItem
  438.             
  439.             if (( iType & 0x80 ) == 0 )
  440.                 ClickItem( item );
  441.         }
  442.     }
  443.     
  444.     // see if any user action resulted in a request to dismiss the dialog. This is quite common-
  445.     // e.g. a double-click in a list, etc. To close safely, we need to action this right at the end
  446.     // of processing a click. To work this, set signalDismiss to ok or cancel in response to your
  447.     // action- do not call Close directly or things may not work as you expect, or worse, crash.
  448.     
  449.     if (( item != ok ) && ( item != cancel ) && ( signalDismiss > 0 ))
  450.         FakeClick( signalDismiss );
  451. }
  452.  
  453.  
  454. /*---------------------------------***  ACTIVATE  ***-----------------------------------*/
  455. /*    
  456. activates TextEdit if present
  457. ----------------------------------------------------------------------------------------*/
  458.  
  459. void    ZDialog::Activate()
  460. {
  461.     if ( macWindow )
  462.     {
  463.         Focus();
  464.         
  465.         DialogPeek    dp = (DialogPeek) macWindow;
  466.         
  467.         if ( HasEditFields())
  468.         {
  469.             ZGrafState    zg;
  470.             
  471.             SetTEItemDataFromIctb( dp->editField + 1 , TRUE );
  472.             TEActivate( dp->textH );
  473.         }
  474.             
  475.         EnableItem( 0 );
  476.     }
  477.     
  478.     ZWindow::Activate();
  479. }
  480.  
  481.  
  482. /*--------------------------------***  DEACTIVATE  ***----------------------------------*/
  483. /*    
  484. deactivates TextEdit if present
  485. ----------------------------------------------------------------------------------------*/
  486.  
  487. void    ZDialog::Deactivate()
  488. {
  489.     ZWindow::Deactivate();
  490.     
  491.     if ( macWindow )
  492.     {
  493.         Focus();
  494.         DisableItem( 0 );
  495.         
  496.         DialogPeek    dp = (DialogPeek) macWindow;
  497.         
  498.         if ( HasEditFields())
  499.         {
  500.             ZGrafState    zg;
  501.             
  502.             SetTEItemDataFromIctb( dp->editField + 1 , TRUE );
  503.             TEDeactivate( dp->textH );
  504.         }
  505.     }
  506. }
  507.  
  508.  
  509. /*-----------------------------------***  IDLE  ***-------------------------------------*/
  510. /*    
  511. blink TextEdit cursor if present
  512. ----------------------------------------------------------------------------------------*/
  513.  
  514. void    ZDialog::Idle()
  515. {
  516.     if ( macWindow )
  517.     {
  518.         Focus();
  519.         
  520.         DialogPeek    dp = (DialogPeek) macWindow;
  521.         
  522.         if ( HasEditFields())
  523.         {
  524.             ZGrafState    zg;
  525.             
  526.             SetTEItemDataFromIctb( dp->editField + 1 , TRUE );
  527.             TEIdle( dp->textH );
  528.         }
  529.     }
  530. }
  531.  
  532.  
  533. /*-----------------------------------***  TYPE  ***-------------------------------------*/
  534. /*    
  535. pass TextEdit the typed character if present. If tab key, cycle through fields
  536. ----------------------------------------------------------------------------------------*/
  537.  
  538. void    ZDialog::Type( const char theKey, const short modifiers )
  539. {
  540.     if ( macWindow )
  541.     {
  542.         DialogPeek    dp = (DialogPeek) macWindow;
  543.         short        iType;
  544.         Handle        iHand;
  545.         Rect        iBox;
  546.         
  547.         Focus();
  548.         
  549.         if ( HasEditFields())
  550.         {
  551.             if ( theKey == TAB_KEY )        // tab
  552.             {
  553.                 short        nextField, fMax;
  554.                 Boolean        reverseTab;
  555.                 
  556.                 reverseTab = ( modifiers & shiftKey ) == shiftKey;
  557.                 
  558.                 // find the next edit field item that can be set
  559.                 
  560.                 if ( reverseTab )
  561.                     nextField = dp->editField;
  562.                 else
  563.                     nextField = dp->editField + 2;
  564.                 
  565.                 fMax = CountDITL( macWindow );
  566.                 
  567.                 do
  568.                 {
  569.                     if ( nextField < 1 )
  570.                         nextField = fMax;
  571.                     
  572.                     if ( nextField > fMax )
  573.                         nextField = 1;
  574.                     
  575.                     // if we got back to where we started, so nothing. This will occur
  576.                     // if the dialog has only 1 edit field
  577.                     
  578.                     if ( nextField == dp->editField + 1 )
  579.                         return;
  580.                     
  581.                     GetDialogItem( macWindow, nextField, &iType, &iHand, &iBox );
  582.                     
  583.                     // if this is an edit field, then select that one
  584.                     
  585.                     if (( iType & 0x7F ) == editText && ( iBox.left < 8192 ))
  586.                     {
  587.                         SelectItem( nextField );
  588.                         break;    
  589.                     }
  590.                     
  591.                     if ( reverseTab )
  592.                         nextField--;
  593.                     else
  594.                         nextField++;
  595.                 }
  596.                 while( 1 );
  597.             }
  598.             else
  599.             {
  600.                 if ( dp->textH )
  601.                 {
  602.                     // if the field being targetted has some special flags set such as
  603.                     // numeric only, etc, this is where we enforce it. Keys that are illegal
  604.                     // according to the field's flags result in a beep and are not passed
  605.                     // on to the TextEdit record.
  606.                     
  607.                     char    k = theKey;
  608.                     
  609.                     if ( KeyIsLegal( &k, dp->editField + 1 ))
  610.                     {
  611.                         // return, enter and escape are never passed to the field, but are
  612.                         // not treated as "illegal" as such...
  613.                         
  614.                         if ( theKey != RETURN_KEY     &&
  615.                              theKey != ENTER_KEY    &&
  616.                              theKey != ESCAPE_KEY )
  617.                         {
  618.                             ZGrafState        zg;
  619.                             unsigned short    f;
  620.                             TEHandle        th;
  621.                             long            mx;
  622.                                 
  623.                             SetTEItemDataFromIctb( dp->editField + 1, TRUE );
  624.                             TEKey( k, dp->textH );
  625.                             
  626.                             // if the field is a password field, echo the true character
  627.                             // to the field's mirror.
  628.                             
  629.                             GetEditFieldInfo( dp->editField + 1, &f, (long*) &th, &mx );
  630.                             
  631.                             if (( f & editFieldHCMirrorAlloc ) && ( th != NULL ))
  632.                             {
  633.                                 (*th)->selStart = (*dp->textH)->selStart;        
  634.                                 (*th)->selEnd = (*dp->textH)->selEnd;
  635.                                 TEKey( theKey, th );
  636.                             }
  637.                         }
  638.                     }
  639.                     else
  640.                         SysBeep( 1 );
  641.                 }
  642.             }
  643.             
  644.             ClipRect( &macWindow->portRect );
  645.             
  646.             // if item is enabled, call ClickItem too
  647.             
  648.             GetDialogItem( macWindow, dp->editField + 1, &iType, &iHand, &iBox );
  649.             
  650.             if (( iType & 0x80 ) == 0 )
  651.                 ClickItem( dp->editField + 1 );
  652.         }
  653.     }
  654. }
  655.  
  656.  
  657.  
  658. /*------------------------------***  DRAWUSERITEM  ***----------------------------------*/
  659. /*    
  660.  
  661. this is called to update each user item in the dialog. You can override this to draw
  662. custom dialog items. The default method draws a 50% grey outline around the item.
  663. ----------------------------------------------------------------------------------------*/
  664.  
  665. void    ZDialog::DrawUserItem( const short item )
  666. {
  667.     short        itemType, p;
  668.     Handle        itemHand;
  669.     Rect        itemBox;
  670.     RgnHandle    clipAbove, temp;
  671.     ZGrafState    gs;
  672.     
  673.     // as a real service to programmers, we clip out all items from the dialog with IDs
  674.     // lower than this user item. This allows us to define a border that intersects other
  675.     // items and we don't need to worry about whether it will draw over them- it won't.
  676.     
  677.     clipAbove = NewRgn();
  678.     temp = NewRgn();
  679.     
  680.     for( p = 1; p < item; p++ )
  681.     {
  682.         GetItemBounds( p, &itemBox );
  683.         RectRgn( temp, &itemBox );
  684.         UnionRgn( clipAbove, temp, clipAbove );
  685.     }
  686.     
  687.     GetClip( temp );
  688.     DiffRgn( temp, clipAbove, temp );
  689.     SetClip( temp );
  690.     
  691.     DisposeRgn( clipAbove );
  692.     DisposeRgn( temp );
  693.     
  694.     // ok, now draw this item...
  695.     
  696.     GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  697.     
  698.     // if the background of the window is not white, and the compiler flag is
  699.     // set, draw a 3D effect line instead of a 50% gray one.
  700.     
  701.     #ifdef _GREYSCALE_APPEARANCE
  702.     
  703.     // if the item is a disabled edit field, grey out the text and draw a grey border
  704.     
  705.     unsigned short    iFlags;
  706.     
  707.     GetEditFieldInfo( item, &iFlags );
  708.     AuxWinHandle    awH;
  709.     RGBColor        rc;
  710.     GDHandle        gdH;
  711.     
  712.     if ((( itemType & 0x7F ) == statText ) && ( iFlags & editFieldIsDisabled ))
  713.     {
  714.         SetTEItemDataFromIctb( item, TRUE );
  715.         PenMode( patBic );
  716.         PenPat( &qd.gray );
  717.         PaintRect( &itemBox );
  718.         PenNormal();
  719.         InsetRect( &itemBox, -3, -3 );
  720.         rc.red = rc.green = rc.blue = 0x7F7F;    // mid grey
  721.         RGBForeColor( &rc );
  722.     }
  723.     else
  724.     {
  725.         if ( IsColourPort( macWindow) && GetAuxWin( macWindow, &awH ))
  726.         {
  727.             Rect        gib;
  728.             RGBColor    rgbContent;
  729.             
  730.             gib = itemBox;
  731.             LocalToGlobal( &topLeft( gib ));
  732.             LocalToGlobal( &botRight( gib ));
  733.             gdH = GetMaxDevice( &gib );
  734.             
  735.             rgbContent = (*(*awH)->awCTable)->ctTable[0].rgb;
  736.             rc.red = rc.green = rc.blue = 0xFFFF;
  737.             
  738.             GetGray( gdH, &rgbContent, &rc );
  739.             
  740.             RGBForeColor( &rc );
  741.             OffsetRect( &itemBox, 1, 1 );
  742.             FrameRect( &itemBox );    
  743.             OffsetRect( &itemBox, -1, -1 );
  744.             
  745.             rc.red = rc.green = rc.blue = 0;
  746.             GetGray( gdH, &rgbContent, &rc );
  747.             RGBForeColor( &rc );
  748.         }
  749.         else
  750.         {
  751.             PenNormal();
  752.             PenPat( &qd.gray );
  753.             PenSize( 1,1 );
  754.         }
  755.     }
  756.     FrameRect( &itemBox );
  757.  
  758.     #else
  759.     
  760.     PenNormal();
  761.     PenPat( &qd.gray );
  762.     PenSize( 1,1 );
  763.     
  764.     // if the item is a disabled edit field, grey out the text and draw a grey border
  765.     
  766.     unsigned short    iFlags;
  767.     
  768.     GetEditFieldInfo( item, &iFlags );
  769.     
  770.     if ((( itemType & 0x7F ) == statText ) && ( iFlags & editFieldIsDisabled ))
  771.     {
  772.         PenMode( patBic );
  773.         PaintRect( &itemBox );
  774.         PenMode( patCopy );
  775.         InsetRect( &itemBox, -3, -3 );
  776.     }
  777.     
  778.     FrameRect( &itemBox );
  779.     
  780.     #endif
  781. }
  782.  
  783.  
  784. /*----------------------------------***  DOCUT  ***-------------------------------------*/
  785. /*    
  786. handle edit command cut.
  787. ----------------------------------------------------------------------------------------*/
  788.  
  789. void    ZDialog::DoCut()
  790. {
  791.     DialogCut( macWindow );
  792.     gClipboard->Clear();
  793.     
  794.     FailOSErr( TEToScrap());
  795. }
  796.  
  797.  
  798. /*----------------------------------***  DOCOPY  ***------------------------------------*/
  799. /*    
  800. handle edit command copy.
  801. ----------------------------------------------------------------------------------------*/
  802.  
  803. void    ZDialog::DoCopy()
  804. {
  805.     DialogCopy( macWindow );
  806.     gClipboard->Clear();
  807.     FailOSErr( TEToScrap());
  808. }
  809.  
  810.  
  811. /*---------------------------------***  DOPASTE  ***------------------------------------*/
  812. /*    
  813. handle edit command paste.
  814. ----------------------------------------------------------------------------------------*/
  815.  
  816. void    ZDialog::DoPaste()
  817. {
  818.     DialogPeek    dp = (DialogPeek) macWindow;
  819.     
  820.     if ( PasteDataIsLegal( dp->editField + 1 ))
  821.     {
  822.         FailOSErr( TEFromScrap());
  823.         SetTEItemDataFromIctb( dp->editField + 1, TRUE );
  824.         DialogPaste( macWindow );
  825.     }
  826.     else
  827.         SysBeep( 1 );
  828. }
  829.  
  830.  
  831. /*---------------------------------***  DOCLEAR  ***------------------------------------*/
  832. /*    
  833. handle edit command clear.
  834. ----------------------------------------------------------------------------------------*/
  835.  
  836. void    ZDialog::DoClear()
  837. {
  838.     DialogDelete( macWindow );
  839. }
  840.  
  841.  
  842. /*-------------------------------***  DOSELECTALL  ***----------------------------------*/
  843. /*    
  844. handle edit command select all by hiliting all text in current field.
  845. ----------------------------------------------------------------------------------------*/
  846.  
  847. void    ZDialog::DoSelectAll()
  848. {
  849.     DialogPeek    dp = (DialogPeek) macWindow;
  850.     SelectDialogItemText( macWindow, dp->editField + 1, 0, 32767 );
  851. }
  852.  
  853. /*-------------------------------***  UPDATEMENUS  ***----------------------------------*/
  854. /*    
  855. enable the edit menu items if we have edit fields
  856. ----------------------------------------------------------------------------------------*/
  857.  
  858. void    ZDialog::UpdateMenus()
  859. {
  860.     // enable cut, copy, clear IF we have edit fields. If modal,
  861.     // do NOT pass this on up the chain.
  862.     
  863.     if ( HasEditFields())
  864.     {
  865.         gMenuBar->EnableCommand( kCmdCut );
  866.         gMenuBar->EnableCommand( kCmdCopy );
  867.         gMenuBar->EnableCommand( kCmdClear );
  868.         gMenuBar->EnableCommand( kCmdSelectAll );
  869.         
  870.         if ( CanPasteType())
  871.             gMenuBar->EnableCommand( kCmdPaste );
  872.     }
  873.     
  874.     if ( !isModal )
  875.         ZWindow::UpdateMenus();
  876. }
  877.  
  878.  
  879. /*-------------------------------***  CANPASTETYPE  ***---------------------------------*/
  880. /*    
  881. we can paste if we have edit fields and there is text on the clipboard
  882. ----------------------------------------------------------------------------------------*/
  883.  
  884. Boolean    ZDialog::CanPasteType()
  885. {
  886.     return ( HasEditFields() && gClipboard->QueryType( 'TEXT' ));
  887. }
  888.  
  889.  
  890. /*----------------------------------***  SETUP  ***-------------------------------------*/
  891. /*    
  892.  
  893. called when the dialog is built so you can initialise your dialog items. For user items,
  894. override DrawUserItem rather than installing your own procs here. By default, this hilites
  895. the text of the first edit field it finds.
  896. ----------------------------------------------------------------------------------------*/
  897.  
  898. void    ZDialog::SetUp()
  899. {
  900.     // set the first edit field to be hilited
  901.     
  902.     short    i, iType, items = CountDITL( macWindow );
  903.     Handle    iHand;
  904.     Rect    iBox;
  905.     
  906.     for ( i = 1; i <= items; i++ )
  907.     {
  908.         GetDialogItem( macWindow, i, &iType, &iHand, &iBox );
  909.     
  910.         if (( iType & 0x7F ) == editText )
  911.         {
  912.             SelectItem( i );
  913.             break;
  914.         }
  915.     }
  916.     // override this method to initialise your controls, etc to the desired
  917.     // state for your dialog, but call the inherited method as well.
  918.     
  919.     long    id = (long) windID << 16;
  920.     
  921.     SendMessage( kMsgDialogSetUp, &id );
  922. }
  923.  
  924.  
  925. /*-----------------------------***  ADJUSTCURSOR  ***-----------------------------------*/
  926. /*    
  927.  
  928. overrides ZWindow to set the cursor to an i-beam over edit fields.
  929. ----------------------------------------------------------------------------------------*/
  930.  
  931. void    ZDialog::AdjustCursor( const Point mouse, const short modifiers )
  932. {
  933.     short        item, itemType;
  934.     Handle        itemHand;
  935.     Rect        itemBox;
  936.     
  937.     item = FindItem( mouse );
  938.     
  939.     if ( item > 0 )
  940.     {
  941.         GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  942.         
  943.         if (( itemType & 0x7F ) == editText )
  944.         {
  945.             PauseCursorAnimation( iBeamCursor );
  946.             return;
  947.         }
  948.     }
  949.     
  950.     ZWindow::AdjustCursor( mouse, modifiers );
  951. }
  952.  
  953.  
  954. /*--------------------------------***  CLICKITEM  ***-----------------------------------*/
  955. /*    
  956.  
  957. an enabled item was clicked (or an enabled field was typed in) This handles check boxes
  958. by toggling their state, and OK and Cancel buttons in modal dialogs. It also now handles
  959. groups of radio buttons. Override to handle clicks in other dialog items, but call the
  960. inherited method to deal with these standard items.
  961. ----------------------------------------------------------------------------------------*/
  962.  
  963. void    ZDialog::ClickItem( const short theItem )
  964. {
  965.     short        itemType;
  966.     Handle        itemHand;
  967.     Rect        itemBox;
  968.     GrafPtr        savePort;
  969.     
  970.     GetPort( &savePort );
  971.     SetPort( macWindow );
  972.     
  973.     // get info about the item clicked
  974.     
  975.     GetDialogItem( macWindow, theItem, &itemType, &itemHand, &itemBox );
  976.     
  977.     // if a checkbox, toggle its state
  978.     
  979.     if (( itemType & 0x7F ) == ( ctrlItem + chkCtrl ))
  980.         SetControlValue(( ControlHandle ) itemHand, GetControlValue(( ControlHandle ) itemHand ) ^ 1 );
  981.         
  982.     // if the item is a radio button, handle it if it is part of a group
  983.     
  984.     if (( itemType & 0x7F ) == ( ctrlItem + radCtrl ))
  985.     {
  986.         // check that the control is actually enabled
  987.         
  988.         if ((*( ControlHandle ) itemHand )->contrlHilite != 255 )
  989.             HandleRButtonGroupClick( theItem );
  990.     }
  991.     // if it is the OK or cancel button, dismiss the dialog if a modal dialog.
  992.     
  993.     if ((( theItem == ok ) || ( theItem == cancel ))    &&
  994.         (( itemType & 0x7F ) == ( ctrlItem + btnCtrl )) &&
  995.         isModal )
  996.     {
  997.         exitItem = theItem;
  998.         
  999.         if ( theItem == ok )
  1000.             Close( kRunning );                // verifies dialog
  1001.         else
  1002.         {
  1003.             dirty = FALSE;                    // suppress save check
  1004.             SendMessage( kMsgDialogCancelled, &windID );
  1005.             ZWindow::Close( kRunning );        // does not verify dialog
  1006.         }
  1007.     }
  1008.     else
  1009.     {
  1010.         // for other items, send a message about the click. This allows a dialog's boss
  1011.         // to implement dialog features without needing to override the dialog itself
  1012.         // for simpler types of dialog. <msgData> is dialog ID in high word, and item
  1013.         // ID in low word of pointer to long.
  1014.         
  1015.         long di = ((long) windID << 16 ) | theItem;
  1016.         SendMessage( kMsgDialogItemClicked, &di );
  1017.     }
  1018.     
  1019.     SetPort( savePort );
  1020. }
  1021.  
  1022.  
  1023. /*---------------------------------***  RUNMODAL  ***-----------------------------------*/
  1024. /*    
  1025. Handle events until OK/Cancel is clicked. Do not abuse this method! Normally you should
  1026. let dialogs work modelessly (even if modal) and not create dialogs "inline". For some
  1027. simple cases it is convenient to create inline dialogs, in which case you can call this to
  1028. implement a holding loop which returns TRUE for OK, FALSE for Cancel. This will return
  1029. immediately for non-modal dialogs
  1030. ----------------------------------------------------------------------------------------*/
  1031.  
  1032. Boolean    ZDialog::RunModal()
  1033. {
  1034.     Boolean        okClicked = FALSE;
  1035.     ZDialog*    topDialog;
  1036.     
  1037.     if ( isModal )
  1038.     {
  1039.         isInline = TRUE;    // caller is responsible for deleting this
  1040.         
  1041.         // The recommended way to do simple dialogs is to wait for the kMsgDialogSuccessfullyClosed
  1042.         // message in the dialog's boss and respond there, or else subclass ZDialog to implement the
  1043.         // relevant actions/processing there. The inline technique should only be considered for
  1044.         // the simplest of dialogs, e.g. those that request a user parameter to a following function.
  1045.         
  1046.         do
  1047.         {
  1048.             gApplication->Process1Event();
  1049.             topDialog = (ZDialog*) gApplication->GetFrontWindow();
  1050.         }
  1051.         while(( topDialog == this ) && IsVisible());
  1052.         
  1053.         okClicked = ( exitItem == ok );
  1054.     }
  1055.     
  1056.     return okClicked;
  1057. }
  1058.  
  1059.  
  1060. /*-------------------------------***  DISMISSMODAL  ***---------------------------------*/
  1061. /*
  1062. Force a modal dialog session to end by passing it a dismissal code (either "ok" or
  1063. "cancel". This calls ClickItem on that item, hence triggering the dialog dismissal. This
  1064. is very rarely needed- you are discouraged from using this to get rid of dialogs- normally
  1065. they will look after themselves without explicit coding for dismissal.    
  1066. ----------------------------------------------------------------------------------------*/
  1067.  
  1068. void    ZDialog::DismissModal( const short itemDismiss )
  1069. {
  1070.     if ( isModal )
  1071.         FakeClick( itemDismiss );
  1072. }
  1073.  
  1074.  
  1075. /*-------------------------------***  CLOSEDIALOG  ***----------------------------------*/
  1076. /*    
  1077.  
  1078. the dialog is about to close. You can abort the close by returning FALSE. Override to
  1079. read the values of controls, other items, etc.
  1080. ----------------------------------------------------------------------------------------*/
  1081.  
  1082. Boolean    ZDialog::CloseDialog()
  1083. {
  1084.     // the dialog is about to close. Return FALSE if you can't close (Verify fields?)
  1085.     // we check if there are any fields that have limits set and are some kind of
  1086.     // numeric field. If the limits have been exceeded by the user's entry, we
  1087.     // hilite the offending field, make a noise and prevent the dialog from closing.
  1088.     
  1089.     if ( HasEditFields())
  1090.     {
  1091.         short             item;
  1092.     
  1093.         item = CountDITL( macWindow );
  1094.  
  1095.         while( item )
  1096.         {
  1097.             if ( ! ValidateItem( item, TRUE ))
  1098.                 return FALSE;
  1099.                     
  1100.             item--;
  1101.         }
  1102.     }
  1103.     
  1104.     SendMessage( kMsgDialogSuccessfullyClosed, &windID );
  1105.     
  1106.     return TRUE;
  1107. }
  1108.  
  1109.  
  1110. /*----------------------------------***  CLOSE  ***-------------------------------------*/
  1111. /*    
  1112.  
  1113. overrides ZWindow so that closing the dialog correctly maintains the chain of command.
  1114. This is called when a modeless dialog is closed from the Close menu, or go-away box, or
  1115. when OK was clicked in a modal dialog. 
  1116. ----------------------------------------------------------------------------------------*/
  1117.  
  1118. Boolean    ZDialog::Close( const short phase )
  1119. {
  1120.     // called for a modeless dialog. This calls CloseDialog. If TRUE, the object is
  1121.     // deleted. This overrides the similar method in ZWindow.
  1122.     
  1123.     Boolean    wasClosed = CloseDialog();
  1124.     
  1125.     if ( wasClosed )
  1126.     {
  1127.         // if the dialog is inline, the caller is responsible for deleting it. In which case
  1128.         // we simply hide ourselves and will get deleted later.
  1129.         
  1130.         if ( isInline )
  1131.             Hide();
  1132.         else
  1133.             ZWindow::Close( phase );
  1134.     }
  1135.         
  1136.     return wasClosed;
  1137. }
  1138.  
  1139.  
  1140. /*-------------------------------***  VALIDATEITEM  ***---------------------------------*/
  1141. /*    
  1142.  
  1143. For an edit field item, this validates that the contents are acceptable within any
  1144. constraints that may be set for the field, returning TRUE if OK, FALSE otherwise. For
  1145. other types of item, this always returns TRUE. Called by CloseDialog(), but you can
  1146. call it at any time you need to check the bounds of a field. If <showAlert> is TRUE,
  1147. this also reports the bounds limits to the user if validation fails.
  1148. ----------------------------------------------------------------------------------------*/
  1149.  
  1150. Boolean    ZDialog::ValidateItem( const short item, Boolean showAlert )
  1151. {
  1152.     short            iType;
  1153.     Boolean            result = TRUE;
  1154.     unsigned short    iFlags;
  1155.     long            val, min, max;
  1156.     
  1157.     iType = GetItemType( item ) & 0x7F;
  1158.     
  1159.     if ( iType == editText )
  1160.     {    
  1161.         GetEditFieldInfo( item, &iFlags, &min, &max );
  1162.         
  1163.         // is this some kind of limiting field?
  1164.         
  1165.         if ( iFlags & ( editFieldHasMinValue + editFieldHasMaxValue ) && ( iFlags & editFieldIsDisabled ) == 0 )
  1166.         {
  1167.             // it's a limiting field, so check the limits. The field is assumed to
  1168.             // contain some kind of integer value- other flags must be set to
  1169.             // ensure that the user can't type bad characters here.
  1170.             
  1171.             val = GetValue( item );
  1172.     
  1173.             if ((( iFlags & editFieldHasMinValue ) && ( val < min )) ||
  1174.                 (( iFlags & editFieldHasMaxValue ) && ( val > max )))
  1175.             {
  1176.                 // limits violated, so prevent closure
  1177.                 // set up the wording of the alert...
  1178.                 
  1179.                 result = FALSE;
  1180.                 
  1181.                 if ( showAlert )
  1182.                 {
  1183.                     Str15     ma, mb;
  1184.                     Str32    sa, sb;
  1185.                     
  1186.                     NumToString( min, ma );
  1187.                     NumToString( max, mb );
  1188.                     
  1189.                     if (( iFlags & ( editFieldHasMinValue + editFieldHasMaxValue )) ==
  1190.                                    ( editFieldHasMinValue + editFieldHasMaxValue ))
  1191.                     {
  1192.                         GetIndString( sa, 128, 14 );
  1193.                         GetIndString( sb, 128, 15 );
  1194.                     }
  1195.                     else
  1196.                     {
  1197.                         sb[0] = 0;
  1198.                         mb[0] = 0;
  1199.                         
  1200.                         if ( iFlags & editFieldHasMinValue )
  1201.                             GetIndString( sa, 128, 12 );
  1202.                         else
  1203.                         {
  1204.                             GetIndString( sa, 128, 13 );
  1205.                             NumToString( max, ma );
  1206.                         }
  1207.                     }
  1208.                     
  1209.                     ParamText( sa, ma, sb, mb );
  1210.                     NotifyAlert( kFieldRangeAlertID );
  1211.                 }
  1212.                 else
  1213.                     SysBeep( 1 );
  1214.                 
  1215.                 // set the value in the field to a legal one...
  1216.                 SetValue( item, MIN( MAX( val, min ), max ));
  1217.                 SelectItem( item );
  1218.             }
  1219.         }
  1220.     }
  1221.     
  1222.     return result;
  1223. }
  1224.  
  1225.  
  1226. /*---------------------------------***  FILTER  ***-------------------------------------*/
  1227. /*    
  1228.  
  1229. now's your chance! This allows you to examine and modify the event that is going to come to
  1230. this dialog before the dialog manager gets it. By default, this maps return and enter keys
  1231. to the dialog buttons. If the event is fully handled, return TRUE, else FALSE. If TRUE is
  1232. returned, no further processing will occur.
  1233. ----------------------------------------------------------------------------------------*/
  1234.  
  1235. Boolean    ZDialog::Filter( EventRecord* theEvent )
  1236. {
  1237.     char        theKey;
  1238.     Boolean        fullyHandled = FALSE;
  1239.     short        itemType;
  1240.     Handle        itemHand;
  1241.     Rect        itemBox;
  1242.     Boolean        cmdPeriod;
  1243.     
  1244.     // see if command-period is down
  1245.     
  1246.     cmdPeriod = ((theEvent->what == keyDown) &&
  1247.                  isModal &&
  1248.                  ((theEvent->modifiers & cmdKey) == cmdKey ) &&
  1249.                  ((theEvent->message & charCodeMask) == '.'));
  1250.     
  1251.     // map return, enter and escape keys to ok and cancel
  1252.     
  1253.     if ( theEvent->what == keyDown )
  1254.     {
  1255.         theKey = theEvent->message & charCodeMask;
  1256.         
  1257.         if (theKey == RETURN_KEY ||            // return
  1258.             theKey == ENTER_KEY)            // enter
  1259.         {
  1260.             // make sure that item 1 is an enabled button
  1261.             
  1262.             GetDialogItem( macWindow, ok, &itemType, &itemHand, &itemBox );
  1263.             
  1264.             if ( itemType == ( ctrlItem + btnCtrl ) &&
  1265.                 (*(ControlHandle) itemHand)->contrlHilite != 255 )
  1266.             {
  1267.                 FakeClick( ok );
  1268.                 fullyHandled = TRUE;
  1269.             }
  1270.         }
  1271.         
  1272.         if (( theKey == ESCAPE_KEY ) || cmdPeriod )    // escape or command-period
  1273.         {
  1274.             // make sure item 2 is an enabled button
  1275.             
  1276.             GetDialogItem( macWindow, cancel, &itemType, &itemHand, &itemBox );
  1277.             
  1278.             if ( itemType == ( ctrlItem + btnCtrl ) &&
  1279.                 (*(ControlHandle) itemHand)->contrlHilite != 255 )
  1280.             {
  1281.                 FakeClick( cancel );
  1282.                 fullyHandled = TRUE;
  1283.             }
  1284.         }
  1285.     }
  1286.  
  1287.     return fullyHandled;
  1288. }
  1289.  
  1290.  
  1291. /*---------------------------------***  FAKECLICK  ***----------------------------------*/
  1292. /*    
  1293. fake a click on an item (presumably a button).
  1294. ----------------------------------------------------------------------------------------*/
  1295.  
  1296. void    ZDialog::FakeClick( const short item )
  1297. {
  1298.     GrafPtr            savePort;
  1299.     Rect            iBox;
  1300.     
  1301.     GetItemBounds( item, &iBox );
  1302.     
  1303.     GetPort( &savePort );
  1304.     SetPort( macWindow );
  1305.     
  1306.     HiliteItem( item, 1 );
  1307.     MZDelay( 8 );
  1308.     HiliteItem( item, 0 );
  1309.     
  1310.     SetLocalZoomSource( &iBox );
  1311.     SetPort( savePort );
  1312.  
  1313.     ClickItem( item );
  1314. }
  1315.  
  1316.  
  1317. /*--------------------------------***  GETITEMTYPE  ***---------------------------------*/
  1318. /*    
  1319. return the type of the item with ID passed.
  1320. ----------------------------------------------------------------------------------------*/
  1321.  
  1322. short    ZDialog::GetItemType( const short item )
  1323. {
  1324.     short    iType;
  1325.     Handle    iHand;
  1326.     Rect    iRect;
  1327.     
  1328.     GetDialogItem( macWindow, item, &iType, &iHand, &iRect );
  1329.     
  1330.     return iType;
  1331. }
  1332.  
  1333.  
  1334. /*--------------------------------***  SETVALUE  ***------------------------------------*/
  1335. /*    
  1336.  
  1337. sets the value of the dialog item to <value>. This determines the type of the item and
  1338. does the obvious thing.  Various data types are accepted by overloading the parameters,
  1339. though for controls, the value must be between -32767 and +32768 or an exception is thrown.
  1340. ----------------------------------------------------------------------------------------*/
  1341.  
  1342. void    ZDialog::SetValue(const short item, const long value)
  1343. {
  1344.     short    itemType;
  1345.     Handle    itemHand;
  1346.     Rect    itemBox;
  1347.     
  1348.     GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  1349.     
  1350.     // for controls: check that parameter is within range, then set the control value
  1351.     
  1352.     if (( itemType & ctrlItem ) == ctrlItem ) 
  1353.     {
  1354.         if ( value < -32767 || value > 32768 )
  1355.             FailOSErr( paramErr );
  1356.         else
  1357.             SetControlValue(( ControlHandle ) itemHand, value );
  1358.     }
  1359.     else
  1360.     {    
  1361.         // for text items: convert long to string, and set item text
  1362.         
  1363.         if ( itemType & ( editText | statText ))
  1364.         {
  1365.             Str255    iText;
  1366.             
  1367.             NumToString( value, iText );
  1368.             SetDialogItemText( itemHand, iText );
  1369.         }
  1370.     }
  1371. }
  1372.  
  1373.  
  1374. /*--------------------------------***  SETVALUE  ***------------------------------------*/
  1375.  
  1376. void    ZDialog::SetValue( const short item, const Str255 value )
  1377. {
  1378.     short    itemType;
  1379.     Handle    itemHand;
  1380.     Rect    itemBox;
  1381.     
  1382.     GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  1383.     
  1384.     if ( itemType & ( editText | statText ))
  1385.         SetDialogItemText( itemHand, value );
  1386. }
  1387.  
  1388.  
  1389. /*--------------------------------***  SETVALUE  ***------------------------------------*/
  1390.  
  1391. void    ZDialog::SetValue( const short item, const double value )
  1392. {
  1393.     short    itemType;
  1394.     Handle    itemHand;
  1395.     Rect    itemBox;
  1396.     
  1397.     GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  1398.     
  1399.     if (( itemType & ctrlItem ) == ctrlItem )
  1400.     {
  1401.         SetValue( item, (long) value );
  1402.     }
  1403.     else
  1404.     {
  1405.         if ( itemType & ( editText | statText ))
  1406.         {
  1407.             Str255    iText;
  1408.  
  1409.             RealToString( value, iText );
  1410.             SetDialogItemText( itemHand, iText );
  1411.         }
  1412.     }
  1413. }
  1414.  
  1415. /*--------------------------------***  GETVALUE  ***------------------------------------*/
  1416. /*    
  1417.  
  1418. gets the value of the dialog item. This determines the type of the item and
  1419. does the obvious thing. For unknown items, returns 0.
  1420. ----------------------------------------------------------------------------------------*/
  1421.  
  1422. long    ZDialog::GetValue( const short item )
  1423. {
  1424.     short    itemType;
  1425.     Handle    itemHand;
  1426.     Rect    itemBox;
  1427.     
  1428.     GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  1429.     
  1430.     if (( itemType & ctrlItem ) == ctrlItem )
  1431.         return GetControlValue(( ControlHandle ) itemHand );
  1432.         
  1433.     if (( itemType & editText ) == editText )
  1434.     {
  1435.         long    value;
  1436.         Str255    iText;
  1437.         
  1438.         GetDialogItemText( itemHand, iText );
  1439.         StringToNum( iText, &value );
  1440.         
  1441.         return value;
  1442.     }
  1443.     
  1444.     return 0;
  1445. }
  1446.  
  1447.  
  1448. /*-----------------------------***  GETVALUEASTEXT  ***---------------------------------*/
  1449. /*    
  1450. get text of item, or if control, convert value to string first (complementary function to
  1451. GetValue().
  1452. ----------------------------------------------------------------------------------------*/
  1453.  
  1454. void    ZDialog::GetValueAsText( const short item, Str255 aStr )
  1455. {
  1456.     short            iType;
  1457.     Handle            iHand;
  1458.     Rect            iBox;
  1459.     unsigned short    f;
  1460.     TEHandle        th;
  1461.     long            mx;
  1462.     
  1463.     GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  1464.     
  1465.     if ( iType & ( statText | editText ))
  1466.     {
  1467.         // if this is an edit field with the password flag set, return the text
  1468.         // from the mirror instead of the visible field.
  1469.         
  1470.         if ( iType & editText )
  1471.         {
  1472.             GetEditFieldInfo( item, &f, (long*) &th, &mx );
  1473.             
  1474.             if (( f & editFieldHCMirrorAlloc ) && ( th != NULL ))
  1475.             {
  1476.                 GetDialogItemText(( Handle ) th, aStr );
  1477.                 return;
  1478.             }
  1479.         }
  1480.         
  1481.         GetDialogItemText( iHand, aStr );
  1482.     }
  1483.     else
  1484.     {
  1485.         if ( iType & ctrlItem )
  1486.         {
  1487.             long    v = GetValue( item );
  1488.         
  1489.             NumToString( v, aStr );
  1490.         }
  1491.     }
  1492. }
  1493.  
  1494.  
  1495. /*----------------------------***  GETVALUEASFLOAT  ***---------------------------------*/
  1496. /*    
  1497. get text of item, then convert it to a floating point number. This is useful to get real
  1498. numbers from editable text fields, etc.
  1499. ----------------------------------------------------------------------------------------*/
  1500.  
  1501. float    ZDialog::GetValueAsFloat( const short item )
  1502. {
  1503.     Str255    itxt;
  1504.     decimal    d;
  1505.     short    vp, ix = 1;
  1506.     
  1507.     GetValueAsText( item, itxt );
  1508.     
  1509.     // make sure it can be read as a null-terminated string
  1510.     
  1511.     itxt[itxt[0] + 1 ] = 0;
  1512.     
  1513.     str2dec((const char*) itxt, &ix, &d, &vp);
  1514.     return dec2f( &d );
  1515. }
  1516.  
  1517.  
  1518. /*-----------------------------***  GETITEMBOUNDS  ***----------------------------------*/
  1519. /*    
  1520. get rect of item
  1521. ----------------------------------------------------------------------------------------*/
  1522.  
  1523. void    ZDialog::GetItemBounds( const short item, Rect* bounds )
  1524. {
  1525.     short    iType;
  1526.     Handle    iHand;
  1527.     
  1528.     GetDialogItem( macWindow, item, &iType, &iHand, bounds );
  1529. }
  1530.  
  1531.  
  1532. /*--------------------------------***  FINDITEM  ***------------------------------------*/
  1533. /*    
  1534. find the item under the mouse point (local coordinates), 0 if no item there
  1535. ----------------------------------------------------------------------------------------*/
  1536.  
  1537. short    ZDialog::FindItem( const Point localMouse )
  1538. {
  1539.     return ( FindDialogItem( macWindow, localMouse ) + 1);
  1540. }
  1541.  
  1542.  
  1543. /*------------------------------***  HILITEITEM  ***------------------------------------*/
  1544. /*    
  1545. allows controls to be hilited or dimmed
  1546. ----------------------------------------------------------------------------------------*/
  1547.  
  1548. void    ZDialog::HiliteItem(const short item, const short state)
  1549. {
  1550.     short    itemType;
  1551.     Handle    itemHand;
  1552.     Rect    itemBox;
  1553.     
  1554.     GetDialogItem( macWindow, item, &itemType, &itemHand, &itemBox );
  1555.     
  1556.     if (( itemType & ctrlItem ) == ctrlItem )
  1557.     {
  1558.         HiliteControl(( ControlHandle ) itemHand, state );
  1559.         
  1560.         if ( item == ok )
  1561.             OutlineDefaultItem();
  1562.     }
  1563.     else
  1564.     {
  1565.         if ( itemType & editText )
  1566.             SelectItem( item );
  1567.     }
  1568. }
  1569.  
  1570.  
  1571. /*-------------------------------***  HIDEITEM  ***-------------------------------------*/
  1572. /*    
  1573. hides the item entirely
  1574. ----------------------------------------------------------------------------------------*/
  1575.  
  1576. void    ZDialog::HideItem( const short item )
  1577. {
  1578.     HideDialogItem( macWindow, item );
  1579. }
  1580.  
  1581.  
  1582. /*-------------------------------***  SHOWITEM  ***-------------------------------------*/
  1583. /*    
  1584. re-shows a hidden item
  1585. ----------------------------------------------------------------------------------------*/
  1586.  
  1587. void    ZDialog::ShowItem( const short item )
  1588. {
  1589.     ShowDialogItem( macWindow, item );
  1590. }
  1591.  
  1592.  
  1593. /*------------------------------***  ENABLEITEM  ***------------------------------------*/
  1594. /*    
  1595. enables a dialog item. If a control, it is undimmed. If static text, it is made into an
  1596. editable field and undimmed. This can also be used to enable entire groups of controls
  1597. by passing the negative of the group ID. Also, pass 0 to enable everything.
  1598. ----------------------------------------------------------------------------------------*/
  1599.  
  1600. void    ZDialog::EnableItem( const short item )
  1601. {
  1602.     if ( item <= 0 )
  1603.     {
  1604.         // this is a group ID so find all controls in the group and enable them.
  1605.         
  1606.         short    iType, i = CountDITL( macWindow );
  1607.         Handle    iHand;
  1608.         Rect    iBox;
  1609.         short    mask;
  1610.         
  1611.         if ( item == 0 )
  1612.             mask = 0;
  1613.         else
  1614.             mask = 0xFF;
  1615.         
  1616.         while( i )
  1617.         {
  1618.             GetDialogItem( macWindow, i, &iType, &iHand, &iBox );
  1619.             
  1620.             if ((( iType & ctrlItem ) == ctrlItem ) && (((*dItemInfo)[i - 1].groupID & mask ) == -item ))
  1621.             {
  1622.                 // pop the state history:
  1623.                 
  1624.                 Boolean state = (*dItemInfo)[i - 1].minValue & 1;
  1625.                 (*dItemInfo)[i - 1].minValue >>= 1;
  1626.                 
  1627.                 HiliteItem( i, state? 255 : 0 );
  1628.             }
  1629.             i--;
  1630.         }
  1631.     }
  1632.     else
  1633.     {
  1634.         short iType = GetItemType( item ) & 0x7F;
  1635.         
  1636.         if ( iType & ctrlItem )
  1637.             HiliteItem( item, 0 );
  1638.         else
  1639.         {
  1640.             // if this is really a disabled edit field, re-enable it
  1641.             
  1642.             unsigned short     iFlags;
  1643.             long            min, max;
  1644.             
  1645.             GetEditFieldInfo( item, &iFlags, &min, &max );
  1646.         
  1647.             if (( iType == statText ) && ( iFlags & editFieldIsDisabled ))
  1648.             {
  1649.                 // this is a disabled edit field really, so convert it back to an edit field,
  1650.                 // clear the disable flag we are keeping and redraw the item.
  1651.                 
  1652.                 Handle    iHand;
  1653.                 Rect    iBox;
  1654.                 
  1655.                 GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  1656.                 iType = ( iType & 0x80 ) | editText;
  1657.                 SetDialogItem( macWindow, item, iType, iHand, &iBox );
  1658.                 
  1659.                 // clear the private disable flag:
  1660.                 
  1661.                 iFlags &= ~editFieldIsDisabled;
  1662.                 SetEditFieldInfo( item, iFlags, min, max );
  1663.                 DrawOneItem( item );
  1664.             }
  1665.         }
  1666.     }
  1667. }
  1668.  
  1669.  
  1670. /*-----------------------------***  DISABLEITEM  ***------------------------------------*/
  1671. /*    
  1672. disables an item. If a control, the control is dimmed. If an edit field, it is converted
  1673. to static text and drawn greyed out (dimmed). This also allows all controls in a group
  1674. to be disabled at once- simply pass the negative of the group ID in. You can disable
  1675. everything by passing 0. Note that the state history of items is stacked to a max depth
  1676. of 32- EnableItem/DisableItem should be used in pairs when used for groups.
  1677. ----------------------------------------------------------------------------------------*/
  1678.  
  1679. void    ZDialog::DisableItem( const short item )
  1680. {
  1681.     if ( item <= 0 )
  1682.     {
  1683.         // this is a group ID so find all controls in the group and disable them. We record
  1684.         // their existing state in the <minValue> field of the item info so we can restore
  1685.         // it in EnableItem. n.b. since the group ID has slightly different meanings in the context
  1686.         // of radio buttons or groups of controls in general, to avoid problems in certain situ-
  1687.         // ations, we only compare the lower 8 bits of the ID. This it is possible to set up
  1688.         // groups that dim as a group, but interact slightly differently if desired.
  1689.         
  1690.         short    iType, i = CountDITL( macWindow );
  1691.         Handle    iHand;
  1692.         Rect    iBox;
  1693.         short    mask;
  1694.         
  1695.         if ( item == 0 )
  1696.             mask = 0;
  1697.         else
  1698.             mask = 0xFF;
  1699.         
  1700.         while( i )
  1701.         {
  1702.             GetDialogItem( macWindow, i, &iType, &iHand, &iBox );
  1703.             
  1704.             if ((( iType & ctrlItem ) == ctrlItem ) && (((*dItemInfo)[i - 1].groupID & mask ) == -item ))
  1705.             {
  1706.                 // push the state history:
  1707.                 
  1708.                 (*dItemInfo)[i - 1].minValue <<= 1;
  1709.                 (*dItemInfo)[i - 1].minValue |= ((*(ControlHandle) iHand)->contrlHilite == 255 )? 1 : 0;
  1710.                 HiliteItem( i, 255 );
  1711.             }
  1712.             
  1713.             i--;
  1714.         }
  1715.     }
  1716.     else
  1717.     {
  1718.         short iType = GetItemType( item ) & 0x7F;
  1719.         
  1720.         if ( iType & ctrlItem )
  1721.             HiliteItem( item, 255 );
  1722.         else
  1723.         {
  1724.             // if this is an edit field, we disable it by converting it to static text and
  1725.             // setting a flag in the private field info. When redrawn, the text will be drawn
  1726.             // greyed out and the border in light grey.
  1727.             
  1728.             if ( iType == editText )
  1729.             {
  1730.                 // one difficulty- if the edit field is the current one, we need to move the
  1731.                 // hilite to another field otherwise strange effects will result which we don't
  1732.                 // want.
  1733.                 
  1734.                 DialogPeek     dp = (DialogPeek) macWindow;
  1735.                 Handle        iHand;
  1736.                 Rect        iBox;
  1737.                 
  1738.                 if ( dp->editField == ( item - 1 ))
  1739.                     Type( TAB_KEY, 0 );        
  1740.  
  1741.                 // now convert it to static:
  1742.                 
  1743.                 GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  1744.                 iType = ( iType & 0x80 ) | statText;
  1745.                 SetDialogItem( macWindow, item, iType, iHand, &iBox );
  1746.                 
  1747.                 // set the disable flag in the private data for the field
  1748.                 
  1749.                 unsigned short  iFlags;
  1750.                 long            min, max;
  1751.                 
  1752.                 GetEditFieldInfo( item, &iFlags, &min, &max );
  1753.                 iFlags |= editFieldIsDisabled;
  1754.                 SetEditFieldInfo( item, iFlags, min, max );
  1755.                 
  1756.                 // now redraw the item to show it in its disabled state. The standard
  1757.                 // user item proc draws the disabled border fo such items.
  1758.                 
  1759.                 DrawOneItem( item );
  1760.                 ZDialog::DrawUserItem( item );
  1761.             }
  1762.         }
  1763.     }
  1764. }
  1765.  
  1766.  
  1767. /*--------------------------***  SETEDITFIELDINFO  ***----------------------------------*/
  1768. /*
  1769. sets additional info about an edit field- for example you can set a field to only accept
  1770. numbers, etc. The flags are a bitfield- you should generally take care to only change
  1771. bits you need to and leave others untouched. Some combinations of bits are not allowed.    
  1772. ----------------------------------------------------------------------------------------*/
  1773.  
  1774. void    ZDialog::SetEditFieldInfo( const short item, unsigned short iFlags, long iMin, long iMax )
  1775. {
  1776.     DItemInfo di;
  1777.     
  1778.     // if the "password field" flag is set, create a mirror TEHandle for the field
  1779.     // if there isn't one already. Under no circumstances change the alloc flag- you can read
  1780.     // it to determine if <min> should be interpreted as a TEHandle, but never change it. YHBW!
  1781.     
  1782.     if (( iFlags & ( editFieldHiddenChars + editFieldHCMirrorAlloc )) == editFieldHiddenChars )
  1783.     {
  1784.         Rect    invR = { 10000, 10000, 10020, 10100 };
  1785.         di.mirrorTE = TENew( &invR, &invR );
  1786.         
  1787.         iFlags |= editFieldHCMirrorAlloc;
  1788.     }
  1789.     else
  1790.         di.minValue = iMin;
  1791.     
  1792.     di.flags = iFlags;
  1793.     di.maxValue = iMax;
  1794.     
  1795.     (*dItemInfo)[item - 1] = di;
  1796. }
  1797.  
  1798.  
  1799. /*--------------------------***  GETEDITFIELDINFO  ***----------------------------------*/
  1800. /*    
  1801. returns info about an edit field as stored in the private data.
  1802. ----------------------------------------------------------------------------------------*/
  1803.  
  1804. void    ZDialog::GetEditFieldInfo( const short item, unsigned short* iFlags, long* iMin, long* iMax )
  1805. {
  1806.     DItemInfo di = (*dItemInfo)[item - 1];
  1807.  
  1808.     *iFlags = di.flags;
  1809.     
  1810.     if ( iMin )
  1811.         *iMin = di.minValue;
  1812.         
  1813.     if ( iMax )
  1814.         *iMax = di.maxValue;
  1815. }
  1816.  
  1817.  
  1818. /*----------------------------***  SETITEMTITLE  ***------------------------------------*/
  1819. /*    
  1820. allows titles of control items to be changed programmatically
  1821. ----------------------------------------------------------------------------------------*/
  1822.  
  1823. void    ZDialog::SetItemTitle( const short item, Str255 title )
  1824. {
  1825.     short     iType;
  1826.     Handle    iHand;
  1827.     Rect    iBox;
  1828.     
  1829.     GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  1830.     
  1831.     if ( iType & ctrlItem )
  1832.         SetControlTitle((ControlHandle) iHand, title );
  1833. }
  1834.  
  1835.  
  1836. /*-----------------------------***  SELECTITEM  ***-------------------------------------*/
  1837. /*    
  1838. if the item is an edit field, this sets it as the current one and selects all the text.
  1839. ----------------------------------------------------------------------------------------*/
  1840.  
  1841. void    ZDialog::SelectItem( const short item )
  1842. {
  1843.     if (( GetItemType( item ) & 0x7F ) == editText )
  1844.     {
  1845.         ZGrafState    zg;
  1846.         
  1847.         if (((DialogPeek) macWindow )->textH )
  1848.         {
  1849.             SetTEItemDataFromIctb( ((DialogPeek) macWindow )->editField + 1 , TRUE );
  1850.             TEDeactivate( ((DialogPeek) macWindow )->textH );
  1851.         }
  1852.             
  1853.         SetTEItemDataFromIctb( item, TRUE );
  1854.         SelectDialogItemText( macWindow, item, 0, 32767 );
  1855.     }
  1856. }
  1857.  
  1858.  
  1859. /*-----------------------***  GETSELECTEDITEMINGROUP  ***-------------------------------*/
  1860. /*    
  1861. returns the item number of the "on" radio button in a group with the given ID. If the
  1862. group represents other kinds of controls, this always returns 0. If a mixed group (i.e
  1863. some radio buttons plus others) this will return the radio button that's on, or 0 if
  1864. none are. This ignores the enabled state of the group or items.
  1865. ----------------------------------------------------------------------------------------*/
  1866.  
  1867. short    ZDialog::GetSelectedItemInGroup( const short groupID )
  1868. {
  1869.     short    iType, i = CountDITL( macWindow );
  1870.     Handle    iHand;
  1871.     Rect    iBox;
  1872.     
  1873.     while( i )
  1874.     {
  1875.         GetDialogItem( macWindow, i, &iType, &iHand, &iBox );
  1876.         
  1877.         if ((( iType & radCtrl ) == radCtrl ) &&
  1878.             ((*dItemInfo)[ i - 1 ].groupID == groupID ) &&
  1879.             GetControlValue((ControlHandle) iHand ) != 0 )
  1880.             return i;
  1881.     
  1882.         i--;
  1883.     }
  1884.     
  1885.     return 0;
  1886. }
  1887.  
  1888.  
  1889.  
  1890. /*--------------------------***  OUTLINEDEFAULTITEM  ***--------------------------------*/
  1891. /*    
  1892. draws the bold border around the item number 1 in the dialog
  1893. ----------------------------------------------------------------------------------------*/
  1894.  
  1895. void    ZDialog::OutlineDefaultItem()
  1896. {
  1897.     short    itemType;
  1898.     Handle    itemHand;
  1899.     Rect    itemBox;
  1900.     
  1901.     GetDialogItem( macWindow, ok, &itemType, &itemHand, &itemBox );
  1902.     
  1903.     // check that this item is a button
  1904.     
  1905.     if ( itemType & ( ctrlItem + btnCtrl ))
  1906.     {
  1907.         Focus();
  1908.         
  1909.         InsetRect( &itemBox, -4, -4 );
  1910.         PenNormal();
  1911.         PenSize( 3, 3 );
  1912.         
  1913.         // if button disabled, draw outline in grey
  1914.         
  1915.         if ((*(ControlHandle) itemHand )->contrlHilite == 255 )
  1916.         {
  1917.             AuxWinHandle    awH;                
  1918.             
  1919.             if ( IsColourPort( macWindow ) && GetAuxWin( macWindow, &awH ))
  1920.             {
  1921.                 RGBColor    midGrey = { 0x7F7F, 0x7F7F, 0x7F7F };
  1922.                 RGBForeColor( &midGrey );
  1923.             }
  1924.             else
  1925.                 PenPat( &qd.gray );
  1926.         }
  1927.         else
  1928.             ForeColor( blackColor );
  1929.         
  1930.         FrameRoundRect( &itemBox, 16, 16 );
  1931.         PenNormal();
  1932.         ForeColor( blackColor );
  1933.     }
  1934. }
  1935.  
  1936.  
  1937. /*-----------------------------***  HASEDITFIELDS  ***----------------------------------*/
  1938. /*    
  1939.  
  1940. returns TRUE if this dialog has any edit fields. Used to determine if Edit commands are
  1941. enabled or not.
  1942.  
  1943. ----------------------------------------------------------------------------------------*/
  1944.  
  1945. Boolean    ZDialog::HasEditFields()
  1946. {
  1947.     // returns TRUE if this dialog has at least one edit field. Use to enable
  1948.     // the edit menu.
  1949.  
  1950.     short    itemType, item;
  1951.     Handle    itemHand;
  1952.     Rect    itemBox;
  1953.     Boolean    hasEF = FALSE;
  1954.  
  1955.     item = CountDITL( macWindow );
  1956.     
  1957.     while(item)
  1958.     {
  1959.         GetDialogItem( macWindow, item--, &itemType, &itemHand, &itemBox );
  1960.     
  1961.         if (( itemType & 0x7F ) == editText &&
  1962.             ( itemBox.left < 8192 ))
  1963.         {
  1964.             hasEF = TRUE;
  1965.             break;
  1966.         }
  1967.     }
  1968.  
  1969.     return hasEF;
  1970. }
  1971.  
  1972.  
  1973. /*-----------------------------***  SETUPRADIOGROUPS  ***-------------------------------*/
  1974. /*    
  1975. This builds the array of radio button groups so that the click handler can correctly
  1976. manage them. This is done very easily- in your DITL resource, add the group ID to the
  1977. button title, separated by a double slash- e.g. My Button//1. This function strips the
  1978. extra characters from the name, so you never see them. Groups start at ID = 1, and
  1979. obviously buttons with the same group ID operate as a set. If you do not extend the title
  1980. of a group button in this way, it will operate in the normal way- i.e. not very well.
  1981.  
  1982. ----------------------------------------------------------------------------------------*/
  1983.  
  1984. void    ZDialog::SetUpRadioGroups( short fromItemNo )
  1985. {
  1986.     short            iType, groupID;
  1987.     Boolean            iDefault;
  1988.     Handle            iHand;
  1989.     Rect            iBox;
  1990.     long            tMin, tMax;
  1991.     unsigned short    tFlags;
  1992.     Str255            cTitle;
  1993.     
  1994.     // scan through looking for buttons and fields (which are also set up here). We scan
  1995.     // backwards for convenience, so to work for the extension case, we stop once we reach
  1996.     // <fromItemNo> + 1, which by default is 0.
  1997.     
  1998.     short    iCount = CountDITL( macWindow );
  1999.     
  2000.     if ( iCount > fromItemNo )
  2001.     {
  2002.         do
  2003.         {
  2004.             GetDialogItem( macWindow, iCount, &iType, &iHand, &iBox );
  2005.             
  2006.             // is this item a radio button or other control? We permit buttons and checkboxes
  2007.             // to have a group ID as well- this can be used to disable or enable sets of
  2008.             // related buttons with one call. The group ID does not affect clicking the item
  2009.             // except for radio buttons.
  2010.             
  2011.             if ( iType & ctrlItem )
  2012.             {
  2013.                 // get the title of the button
  2014.                 
  2015.                 GetControlTitle((ControlHandle) iHand, cTitle );
  2016.                 
  2017.                 // parse the title looking for a double slash followed by a number. This
  2018.                 // is returned in groupID, and the title is stripped of the extra chars.
  2019.                 
  2020.                 ParseRButtonTitle( cTitle, &groupID, &iDefault );
  2021.                 
  2022.                 // set up the entry in the dialog item info table
  2023.                 
  2024.                 (*dItemInfo)[iCount - 1].groupID = groupID;
  2025.                 
  2026.                 // set the button's name to eliminate the grouping info
  2027.                 
  2028.                 SetControlTitle((ControlHandle) iHand, cTitle );
  2029.                 
  2030.                 // if this is the default button, set it ON
  2031.                 
  2032.                 if ( iDefault )
  2033.                     SetControlValue((ControlHandle) iHand, 1 );
  2034.             }
  2035.             else
  2036.             {
  2037.                 // set up info for edit fields from formatted resource string:
  2038.                 
  2039.                 if (( iType & 0x7F ) == editText )
  2040.                 {
  2041.                     GetDialogItemText( iHand, cTitle );
  2042.                     ParseEditFieldInfo( cTitle, &tFlags, &tMin, &tMax );
  2043.                     SetEditFieldInfo( iCount, tFlags, tMin, tMax );
  2044.                     SetDialogItemText( iHand, cTitle );
  2045.                 }
  2046.             }
  2047.         }
  2048.         while( --iCount > fromItemNo );
  2049.     }
  2050. }
  2051.  
  2052.  
  2053. /*---------------------------***  PARSERBUTTONTITLE  ***--------------------------------*/
  2054. /*    
  2055. Finds any group ID "buried" in the button name. This modifies the input string so that
  2056. the extra characters are removed.
  2057. ----------------------------------------------------------------------------------------*/
  2058.  
  2059. void    ZDialog::ParseRButtonTitle( Str255 buttonTitle, short* groupID, Boolean* isDefault )
  2060. {
  2061.     register char    cc = 1;
  2062.     long            gID = 0;
  2063.     Str15            subStr;
  2064.     
  2065.     *groupID = 0;        // in case we find nothing at all
  2066.     *isDefault = FALSE;
  2067.     
  2068.     // scan the string looking for two consecutive forward slashes:
  2069.     
  2070.     do
  2071.     {
  2072.         if ((buttonTitle[cc] == '/') && (buttonTitle[cc + 1] == '/'))
  2073.         {
  2074.             // found two consecutive slashes- now copy the rest of the string into
  2075.             // subStr.    
  2076.             
  2077.             subStr[0] = buttonTitle[0] - cc - 1;    // length of remainder of string
  2078.             if (subStr[0])
  2079.             {    
  2080.                 BlockMoveData(&buttonTitle[cc + 2], &subStr[1], subStr[0]);
  2081.                 
  2082.                 // look to see if this is the default button in the group. This is indicated
  2083.                 // by the ID number being followed by a '*' character.
  2084.                 
  2085.                 if ( subStr[subStr[0]] == '*' )
  2086.                 {
  2087.                     *isDefault = TRUE;
  2088.                     
  2089.                     // remove char from string
  2090.                     
  2091.                     subStr[0]--;
  2092.                 }
  2093.                 else
  2094.                     *isDefault = FALSE;
  2095.             
  2096.                 // convert substring to a number. Note that results are unpredictable if
  2097.                 // the string does not have a pure number following the two slashes.
  2098.                 // e.g. "My Button//hello" will certainly not work!
  2099.                 
  2100.                 StringToNum( subStr, &gID );
  2101.                 
  2102.                 // shorten original string by the amount needed to remove extra
  2103.                 
  2104.                 buttonTitle[0] = cc - 1;
  2105.                 *groupID = LoWord( gID );
  2106.                 
  2107.                 break;
  2108.             }    
  2109.         }
  2110.     }
  2111.     while( ++cc <= buttonTitle[0] );
  2112. }
  2113.  
  2114.  
  2115. /*------------------------***  HANDLERBUTTONGROUPCLICK  ***-----------------------------*/
  2116. /*    
  2117. turns off the buttons in the same group as this item, then turns this one on.
  2118. ----------------------------------------------------------------------------------------*/
  2119.  
  2120. void    ZDialog::HandleRButtonGroupClick( const short item )
  2121. {
  2122.     // <item> is already known to be a radio button, so find its "groupies" and turn them
  2123.     // all off. Then turn this one on.
  2124.  
  2125.     short    groupID, tIndex, gIndex, iType, targetGroup;
  2126.     
  2127.     gIndex = CountDITL( macWindow );
  2128.     targetGroup = (*dItemInfo)[item -1].groupID;
  2129.     
  2130.     // if the target group is 0, do nothing, since user elected to handle these buttons
  2131.     // on his own- silly beggar!
  2132.     
  2133.     if ( targetGroup > 0 )
  2134.     {
  2135.         for( tIndex = 1; tIndex <= gIndex; tIndex++ )
  2136.         {
  2137.             iType = GetItemType( tIndex ) & 0x7F;
  2138.             
  2139.             if ( iType == ( ctrlItem + radCtrl ))
  2140.             {
  2141.                 groupID = (*dItemInfo)[tIndex -1].groupID;
  2142.             
  2143.                 // if this is in our target group, turn it off unless it's the
  2144.                 // one that was just hit
  2145.                 
  2146.                 if ( groupID == targetGroup )
  2147.                 {
  2148.                     if ( tIndex == item )
  2149.                         SetValue( tIndex, 1 );
  2150.                     else
  2151.                         SetValue( tIndex, 0 );
  2152.                 }
  2153.             }
  2154.         }
  2155.     }    
  2156. }
  2157.  
  2158.  
  2159. /*-------------------------***  SETTEITEMDATAFROMICTB  ***------------------------------*/
  2160. /*    
  2161. sets the TextEdit record that is handling the item to the relevant parameters in the
  2162. associated 'ictb' resource. We made a copy of this resource when the dialog was opened.
  2163. WARNING: ensure that the item is an edit text field before calling this!
  2164. ----------------------------------------------------------------------------------------*/
  2165.  
  2166. void    ZDialog::SetTEItemDataFromIctb( const short teItem, Boolean applyChanges )
  2167. {
  2168.     if ( macWindow && IsColourPort( macWindow ) && ictb )
  2169.     {
  2170.         // there is an ictb, so see if this item has a special entry:
  2171.         
  2172.         TEHandle        te;
  2173.         ictbItemEntry    ie;
  2174.         TextStyle        tsRec;
  2175.         
  2176.         te = ((DialogPeek) macWindow)->textH;
  2177.         ie = (*ictb)[ teItem - 1 ];
  2178.         
  2179.         if ( ie.iData != 0 &&
  2180.              ie.iOffset != 0 )
  2181.         {
  2182.             // yes, there is a special setting for this item- what is it?
  2183.             
  2184.             ictbTablePtr    tp;
  2185.             
  2186.             HLock((Handle) ictb );
  2187.             tp = ( ictbTablePtr ) ((Ptr) *ictb + ie.iOffset );
  2188.     
  2189.             // tp is now pointing at the text table for the item. Using this table,
  2190.             // we need to set up a TEStyle record and pass it to TextEdit.
  2191.             
  2192.             // the font is either already known or can be looked up via its name
  2193.             
  2194.             if ( ie.iData & fFamChange )
  2195.             {
  2196.                 if ( ie.iData & fIsFNameOffset )
  2197.                 {
  2198.                     // need to look up the font via the name table. In this case
  2199.                     // txtFont contains the offset to the font's name
  2200.                     
  2201.                     GetFNum((unsigned char*) *ictb + tp->txtFont , &tsRec.tsFont);
  2202.                 }
  2203.                 else
  2204.                     tsRec.tsFont = tp->txtFont;
  2205.             }
  2206.             else
  2207.                 tsRec.tsFont = macWindow->txFont;
  2208.                 
  2209.             // set simple fields
  2210.             
  2211.             if ( ie.iData & fFaceChange )
  2212.                 tsRec.tsFace = tp->txtFace;
  2213.             else
  2214.                 tsRec.tsFace = macWindow->txFace;
  2215.                 
  2216.             if ( ie.iData & fSizeChange )
  2217.                 tsRec.tsSize = tp->txtSize;
  2218.             else
  2219.                 tsRec.tsSize = macWindow->txSize;
  2220.                 
  2221.             // set the colours of the port
  2222.             
  2223.             if ( applyChanges )
  2224.             {
  2225.                 if ( ie.iData & fFColourChange )
  2226.                     RGBForeColor( &tp->txtFColour );
  2227.                 
  2228.                 if ( ie.iData & fBColourChange )
  2229.                     RGBBackColor( &tp->txtBColour );
  2230.             }
  2231.             HUnlock((Handle) ictb );
  2232.         }
  2233.         else
  2234.         {
  2235.             tsRec.tsFace = macWindow->txFace;
  2236.             tsRec.tsFont = macWindow->txFont;
  2237.             tsRec.tsSize = macWindow->txSize;
  2238.             
  2239.             // reset the default colours as well
  2240.             
  2241.             if ( applyChanges )
  2242.             {
  2243.                 AuxWinHandle    aw;
  2244.                 
  2245.                 if ( GetAuxWin( macWindow, &aw ))
  2246.                 {    
  2247.                     RGBColor    rgb = (*(*aw)->awCTable)->ctTable[0].rgb;
  2248.                 
  2249.                     RGBBackColor( &rgb );
  2250.                     ForeColor( blackColor );
  2251.                 }
  2252.             }    
  2253.         }
  2254.         
  2255.         (*te)->txFont = tsRec.tsFont;
  2256.         (*te)->txFace = tsRec.tsFace;
  2257.         (*te)->txSize = tsRec.tsSize;
  2258.         
  2259.         TextFont( tsRec.tsFont );
  2260.         TextFace( tsRec.tsFace );
  2261.         TextSize( tsRec.tsSize );
  2262.         
  2263.         // note: at this point, the lineHeight of the teRec should be calculated for the new
  2264.         // font. The Dialog Manager fails to do this, and the results are poor text alignment
  2265.         // and jumpiness in fields. MacZoop hereby fixes this bug so you no longer need a
  2266.         // workaround:
  2267.         
  2268.         FontInfo    fi;
  2269.         
  2270.         GetFontInfo( &fi );
  2271.         (*te)->lineHeight = fi.ascent + fi.descent + fi.leading;
  2272.         (*te)->fontAscent = fi.ascent;
  2273.         
  2274.         TECalText( te );
  2275.     }
  2276. }
  2277.  
  2278.  
  2279. /*--------------------------***  ADDGREYSCALEEFFECTS  ***-------------------------------*/
  2280. /*    
  2281. adds 3D effect borders to edit text items
  2282. ----------------------------------------------------------------------------------------*/
  2283.  
  2284. void    ZDialog::AddGreyscaleEffects()
  2285. {
  2286.     short            n, iType;
  2287.     Handle            iHand;
  2288.     Rect            r;
  2289.     unsigned short     iFlags;
  2290.     
  2291.     if ( IsColourPort( macWindow ))
  2292.     {
  2293.         SetDefaultColours();
  2294.         n = CountDITL( macWindow );
  2295.     
  2296.         while( n )
  2297.         {
  2298.             GetEditFieldInfo( n, &iFlags );
  2299.             GetDialogItem( macWindow, n--, &iType, &iHand, &r );    
  2300.             
  2301.             if ((( iType & 0x7F ) == editText ) ||
  2302.                ((( iType & 0x7F ) == statText ) && ( iFlags & editFieldIsDisabled )))
  2303.             {
  2304.                 InsetRect( &r, -3, -3 );
  2305.                 FrameGrayRect( &r );
  2306.             }
  2307.         }
  2308.     }
  2309. }
  2310.  
  2311.  
  2312. /*-------------------------------***  KEYISLEGAL  ***-----------------------------------*/
  2313. /*    
  2314. returns TRUE if the key character is permitted in the targetted field according to its
  2315. info flags (set by SetEditFieldInfo). This is called by Type().
  2316. ----------------------------------------------------------------------------------------*/
  2317.  
  2318. Boolean    ZDialog::KeyIsLegal( char* theKey, const short targetItem )
  2319. {
  2320.     Boolean            keyLegal = TRUE;
  2321.     Boolean            numeric;
  2322.     unsigned short    iFlags;
  2323.     short            iType;
  2324.     char            k = *theKey;
  2325.     
  2326.     iType = GetItemType( targetItem ) & 0x7F;
  2327.     
  2328.     if ( iType == editText )
  2329.     {
  2330.         GetEditFieldInfo( targetItem, &iFlags );
  2331.     
  2332.         // if flags are all zero, this is a normal field and all chars are allowed,
  2333.         // otherwise we're limited to certain sets of characters according to exactly
  2334.         // which flags are set.
  2335.         
  2336.         if ( iFlags )
  2337.         {
  2338.             keyLegal = FALSE;
  2339.             numeric = ( k >= '0' && k <= '9' );
  2340.             
  2341.             // alphabetic only eliminates all ascii chars below the @ symbol:
  2342.             
  2343.             if ( iFlags & editFieldAlphabeticOnly )
  2344.                 keyLegal = ( k >= '@' || k < '0' );
  2345.                 
  2346.             // signed integer allows only numbers and - sign
  2347.             
  2348.             if ( iFlags & editFieldSignedInteger )    
  2349.                 keyLegal = numeric || ( k == '-' );
  2350.             
  2351.             // signed float additionally allows decimal point
  2352.                 
  2353.             if ( iFlags & editFieldSignedFloat )
  2354.                 keyLegal = numeric || (k == '-' ) || ( k == '.' );
  2355.             
  2356.             // unsigned integer disallows - sign
  2357.                 
  2358.             if ( iFlags & editFieldUnsignedInteger )
  2359.                 keyLegal = numeric;
  2360.                 
  2361.             // unsigned float allows decimal point but not - sign
  2362.             
  2363.             if ( iFlags & editFieldUnsignedFloat )
  2364.                 keyLegal = numeric || ( k == '.' );
  2365.             
  2366.             // these keys are always considered legal:
  2367.             
  2368.             keyLegal |=  ( k == BACKSPACE_KEY     ||
  2369.                            k == UP_ARROW_KEY    ||
  2370.                            k == DOWN_ARROW_KEY    ||
  2371.                            k == LEFT_ARROW_KEY    ||
  2372.                            k == RIGHT_ARROW_KEY||
  2373.                            k == RETURN_KEY        ||
  2374.                            k == ENTER_KEY        ||
  2375.                            k == ESCAPE_KEY );
  2376.                            
  2377.             // password field? all chars permitted, but transmutes the character. Note that
  2378.             // this feature flag should not be used with any others set.
  2379.             
  2380.             if ( iFlags & editFieldHiddenChars )
  2381.             {
  2382.                 // if not a control character, transmute to a bullet:
  2383.                 
  2384.                 if ( ! keyLegal )
  2385.                     *theKey = '•';
  2386.                 
  2387.                 // all characters legal here
  2388.                 
  2389.                 keyLegal = TRUE;
  2390.             }
  2391.         }
  2392.     }
  2393.     
  2394.     return keyLegal;
  2395. }
  2396.  
  2397.  
  2398. /*----------------------------***  PASTEDATAISLEGAL  ***--------------------------------*/
  2399. /*    
  2400. if the clipboard contains text and the paste target is an edit field, this determines
  2401. if the text is in a legal format according to the info stored for the field. This is used
  2402. to enforce the field restrictions when pasting.
  2403. ----------------------------------------------------------------------------------------*/
  2404.  
  2405. Boolean    ZDialog::PasteDataIsLegal( const short targetItem )
  2406. {
  2407.     Boolean            legalPaste;
  2408.     unsigned short    iFlags;
  2409.     char*            testStr;
  2410.     long            tSize;
  2411.     
  2412.     legalPaste = ZDialog::CanPasteType();
  2413.     
  2414.     if ( legalPaste )
  2415.     {
  2416.         // get the flags for the target field. If zero, this is a normal field and all
  2417.         // text is valid, so there is no need to further test it.
  2418.         
  2419.         GetEditFieldInfo( targetItem, &iFlags );
  2420.         
  2421.         if ( iFlags )
  2422.         {
  2423.             // you can't paste into a password field, so if that flag's set, return FALSE
  2424.             
  2425.             if ( iFlags & editFieldHiddenChars )
  2426.                 return FALSE;
  2427.             
  2428.             // in order to check the text, we need to obtain a copy of it
  2429.             
  2430.             Handle    tx = gClipboard->GetData( 'TEXT' );
  2431.             
  2432.             if ( tx )
  2433.             {
  2434.                 // to test the text, we scan through it and call KeyIsLegal() for each
  2435.                 // character until it returns FALSE, indicating that a bad char was
  2436.                 // found in the text.
  2437.                     
  2438.                 tSize = GetHandleSize( tx );
  2439.                 HLock( tx );
  2440.                 testStr = (char*) *tx;
  2441.                 
  2442.                 while( tSize )
  2443.                 {
  2444.                     if ( !KeyIsLegal( testStr, targetItem ))
  2445.                     {
  2446.                         legalPaste = FALSE;
  2447.                         break;
  2448.                     }
  2449.                     
  2450.                     testStr++;
  2451.                     tSize--;
  2452.                 }
  2453.  
  2454.                 HUnlock( tx );
  2455.                 DisposeHandle( tx );
  2456.             }
  2457.             else
  2458.                 legalPaste = FALSE;
  2459.         }
  2460.     }
  2461.     
  2462.     return legalPaste;
  2463. }
  2464.  
  2465.  
  2466. /*---------------------------***  PARSEEDITFIELDINFO  ***-------------------------------*/
  2467. /*
  2468. extracts set uyp flags and any min or max associated with a field. This is set in the
  2469. resource using a specially formatted string similar to the way button groups work.    
  2470. ----------------------------------------------------------------------------------------*/
  2471.  
  2472. void    ZDialog::ParseEditFieldInfo( Str255 efText, unsigned short* efFlags, long* min, long* max )
  2473. {
  2474.     register char    cc = 1, dc;
  2475.     unsigned char    stPart, ssLen;
  2476.     long            temp;
  2477.     Str15            subStr;
  2478.     
  2479.     *efFlags = 0;
  2480.     *min = 0;
  2481.     *max = 0;
  2482.     
  2483.     do
  2484.     {
  2485.         // scan forward looking for two forward slashes
  2486.         
  2487.         if (( efText[cc] == '/' ) && ( efText[cc + 1] == '/' ))
  2488.         {
  2489.             // found two consecutive slashes- note the length of the info and scan for
  2490.             // delimiters
  2491.             
  2492.             stPart = 0;
  2493.             ssLen = efText[0] - cc + 1;
  2494.             
  2495.             // string will consist of up to three numbers, separated by commas.
  2496.             // the first number is the flags field, the second (optional) the
  2497.             // min limit, and the third (optional) the max limit
  2498.             
  2499.             cc += 2;    
  2500.             dc = cc;
  2501.             
  2502.             while( dc <= efText[0] )
  2503.             {
  2504.                 // scan for the next comma or end of string:
  2505.             
  2506.                 if (( dc >= efText[0] ) || ( efText[ dc + 1 ] == ',' ))
  2507.                 {     
  2508.                     // found a segment- extract it into subStr and convert to number
  2509.                     
  2510.                     subStr[0] = dc - cc + 1;
  2511.                     BlockMoveData( &efText[cc], &subStr[1], dc - cc + 1 );
  2512.                     StringToNum( subStr, &temp );
  2513.                     
  2514.                     // assign it to the relevant parameter
  2515.                     
  2516.                     switch( stPart )
  2517.                     {
  2518.                         case 0:
  2519.                             *efFlags = temp;
  2520.                             break;
  2521.                         
  2522.                         case 1:
  2523.                             *min = temp;
  2524.                             break;
  2525.                             
  2526.                         case 2:
  2527.                             *max = temp;
  2528.                             break;
  2529.                     }
  2530.                     
  2531.                     stPart++;
  2532.                     cc = dc + 2;
  2533.                     dc = cc - 1;
  2534.                 }
  2535.                 
  2536.                 dc++;    
  2537.             }
  2538.             
  2539.             // remove extra data from string:
  2540.             
  2541.             efText[0] -= ssLen;    
  2542.             break;
  2543.         }
  2544.     }
  2545.     while( ++cc <= efText[0] );
  2546. }
  2547.  
  2548.  
  2549. /*---------------------------***  APPENDITEMSTODIALOG  ***------------------------------*/
  2550. /*
  2551. extends the dialog by appending another 'DITL' resource to it. This calls AppendDITL but
  2552. has the additional advantage of allowing our private radio groups and edit-field info
  2553. stuff to work correctly.
  2554. ----------------------------------------------------------------------------------------*/
  2555.  
  2556. void    ZDialog::AppendItemsToDialog( const short ditlID, DITLMethod apMethod )
  2557. {
  2558.     Handle     ditH;
  2559.     short    numAdded, items, existItems, i;
  2560.     Rect    ir, iBounds;
  2561.     
  2562.     existItems = CountDITL( macWindow );
  2563.     
  2564.     FailNILRes( ditH = GetResource( 'DITL', ditlID ));
  2565.     AppendDITL( macWindow, ditH, apMethod );
  2566.     ReleaseResource( ditH );
  2567.     
  2568.     items = CountDITL( macWindow );
  2569.     numAdded = items - existItems;
  2570.     
  2571.     // extend the private data by this many entries
  2572.     
  2573.     long    pdSize = GetHandleSize((Handle) dItemInfo );
  2574.     pdSize += ( sizeof( DItemInfo ) * numAdded ); 
  2575.     SetHandleSize((Handle) dItemInfo, pdSize );
  2576.     FailMemError();
  2577.     
  2578.     for( i = existItems; i < items; i++ )
  2579.     {
  2580.         (*dItemInfo)[i].flags = 0;
  2581.         (*dItemInfo)[i].minValue = 0;
  2582.         (*dItemInfo)[i].maxValue = 0;
  2583.         
  2584.         GetItemBounds( i + 1, &ir );
  2585.         
  2586.         if ( i == existItems )
  2587.             iBounds = ir;
  2588.         else
  2589.             UnionRect( &ir, &iBounds, &iBounds );
  2590.     }
  2591.     // now we need to set up these additional entries with group or field data
  2592.     
  2593.     SetUpUserItems( existItems );
  2594.     SetUpRadioGroups( existItems );
  2595.     
  2596.     InsetRect( &iBounds, -4, -4 );
  2597.     InvalRect( &iBounds );
  2598. }
  2599.  
  2600.  
  2601. /*---------------------------***  REMOVEAPPENDEDITEMS  ***------------------------------*/
  2602. /*
  2603. removes any extra items added by the above routine.
  2604. ----------------------------------------------------------------------------------------*/
  2605.  
  2606. void    ZDialog::RemoveAppendedItems()
  2607. {
  2608.     short    numToRemove, items, i;
  2609.     Rect    iBounds, ir;
  2610.     
  2611.     items = CountDITL( macWindow );
  2612.     numToRemove = items - baseItems;
  2613.     
  2614.     if ( numToRemove > 0 )
  2615.     {
  2616.         for( i = baseItems + 1; i <= items; i++ )
  2617.         {
  2618.             GetItemBounds( i, &ir );
  2619.             
  2620.             if ( i == baseItems + 1 )
  2621.                 iBounds = ir;
  2622.             else
  2623.                 UnionRect( &ir, &iBounds, &iBounds );
  2624.         }
  2625.         
  2626.         ShortenDITL( macWindow, numToRemove );
  2627.         
  2628.         // erase the area encompassed by the items (this step is necessary
  2629.         // if extra 3D effects are present, since they draw outside the items'
  2630.         // borders.
  2631.         
  2632.         InsetRect( &iBounds , -4, -4 );
  2633.         EraseRect( &iBounds );
  2634.         
  2635.         // remove the extra data from the private handle too
  2636.         
  2637.         long    pdSize = GetHandleSize((Handle) dItemInfo );
  2638.         pdSize -= ( sizeof( DItemInfo ) * numToRemove );
  2639.         SetHandleSize((Handle) dItemInfo, pdSize );
  2640.         FailMemError();
  2641.     }
  2642. }
  2643.  
  2644.  
  2645. /*------------------------------***  WRITETOSTREAM  ***---------------------------------*/
  2646. /*
  2647. store dialog in the stream. note this does NOT call ZWindow's WriteToStream method
  2648. ----------------------------------------------------------------------------------------*/
  2649.  
  2650. void    ZDialog::WriteToStream( ZStream* aStream )
  2651. {
  2652. #if _MACZOOP_STREAMS
  2653.     ZCommander::WriteToStream( aStream );
  2654.     
  2655.     // save window state info to the stream. This includes its position, title, visible
  2656.     // and floating flags, ID, etc, etc.
  2657.     
  2658.     short    h, v;
  2659.     Str255    title;
  2660.     
  2661.     // write essential data stored in <macWindow> first...
  2662.     
  2663.     aStream->WriteRect( &macWindow->portRect );
  2664.     
  2665.     aStream->WriteChar( IsVisible());
  2666.     aStream->WriteShort( GetWVariant( macWindow ));
  2667.     GetName( title );
  2668.     aStream->WriteString( title );
  2669.     aStream->WriteChar(((WindowPeek) macWindow )->goAwayFlag );
  2670.     
  2671.     // now we need to stream the items list. For simplicity, what is actually streamed
  2672.     // is the DITL handle for the dialog, which specifies all items. However, in order
  2673.     // to recreate the dialog from this handle, it is necessary to clear the "place holder"
  2674.     // fields to NULL so that NewDialog recreates the various item handles. This is a tad
  2675.     // tedious, but unfortunately necessary.
  2676.     
  2677.     Handle        ditl = ((DialogPeek) macWindow )->items;
  2678.     
  2679.     FailOSErr( HandToHand( &ditl ));
  2680.     
  2681.     ClearDITLPlaceHolders( ditl );
  2682.     aStream->WriteHandle( ditl );
  2683.     DisposeHandle( ditl );
  2684.  
  2685.     // write grafport state
  2686.     
  2687.     aStream->WriteGrafPort( macWindow );
  2688.     
  2689.     // write window colour table, if there is one
  2690.     
  2691.     AuxWinHandle    awH;
  2692.     
  2693.     if ( GetAuxWin( macWindow, &awH ))
  2694.         aStream->WriteHandle((Handle) (*awH)->awCTable );
  2695.     else
  2696.         aStream->WriteHandle( NULL );
  2697.     
  2698.     // write global window position...
  2699.     
  2700.     GetGlobalPosition( &h, &v );
  2701.     aStream->WriteShort( h );
  2702.     aStream->WriteShort( v );
  2703.     
  2704.     // write various window data members...
  2705.     
  2706.     aStream->WriteRect( &sizeRect );
  2707.     aStream->WriteShort( windID );
  2708.     aStream->WriteChar( isNamed );
  2709.     aStream->WriteChar( stationeryFile );
  2710.     aStream->WriteData((Ptr) &macFile, sizeof( FSSpec ));
  2711.     aStream->WriteLong((long) macFType );
  2712.     aStream->WriteChar( printable );
  2713.     aStream->WriteChar( floating );
  2714.     aStream->WriteChar( disableAutoClose );
  2715.     aStream->WriteRect( &zoomSource );
  2716.     
  2717.     // finally, we must write the states and values of all of the dialog items, in order that
  2718.     // we can restore the dialog EXACTLY when it is streamed back in. The basic DITL will have
  2719.     // established the groups for buttons, etc, but still the contents and values of text and
  2720.     // controls is not known.
  2721.     
  2722.     aStream->WriteHandle((Handle) dItemInfo );
  2723.     aStream->WriteHandle((Handle) ictb );
  2724.     
  2725.     for( h = 1; h <= CountDITL( macWindow ); h++ )
  2726.     {
  2727.         v = GetItemType( h ) & 0x7F;
  2728.         
  2729.         switch( v )
  2730.         {
  2731.             case editText:
  2732.             case statText:
  2733.                 // text items are written as strings
  2734.                 GetValueAsText( h, title );
  2735.                 aStream->WriteString( title );
  2736.                 break;
  2737.                 
  2738.             case userItem:
  2739.             case picItem:
  2740.             case iconItem:
  2741.                 // these items are currently not streamed- the correct resources must be present.
  2742.                 // This may change later on [TO DO]
  2743.                 break;
  2744.                 
  2745.             default:
  2746.                 // controls' values are written as longs, control's enable state as a char [TO DO]
  2747.  
  2748.                 aStream->WriteLong( GetValue( h ));
  2749.                 break;
  2750.         }
  2751.     }
  2752. #endif
  2753. }
  2754.  
  2755.  
  2756. /*------------------------------***  READFROMSTREAM  ***--------------------------------*/
  2757. /*
  2758. construct dialog from the stream
  2759. ----------------------------------------------------------------------------------------*/
  2760.  
  2761. void    ZDialog::ReadFromStream( ZStream* aStream )
  2762. {
  2763. #if _MACZOOP_STREAMS
  2764.     ZCommander::ReadFromStream( aStream );
  2765.     
  2766.     Rect        pr;
  2767.     Boolean        vis, goAway;
  2768.     short        varCode, h, v;
  2769.     long        dLen; 
  2770.     Handle        ditl;
  2771.     Str255        title;
  2772.     
  2773.     aStream->ReadRect( &pr );
  2774.     aStream->ReadChar((char*) &vis );
  2775.     aStream->ReadShort( &varCode );
  2776.     aStream->ReadString( title );
  2777.     aStream->ReadChar((char*) &goAway );
  2778.     aStream->ReadHandle( &ditl );
  2779.     
  2780.     FailNIL( ditl );
  2781.     
  2782.     // n.b. dialog assumes ownership of the items list handle
  2783.     
  2784.     MakeMacWindow( &pr, title, FALSE, varCode, goAway, ditl );
  2785.     
  2786.     // read rest of basic window parameters: font, colours, etc
  2787.     
  2788.     aStream->ReadGrafPort( macWindow );
  2789.     
  2790.     // read window colour table, which window becomes owner of
  2791.     
  2792.     WCTabHandle    ct = NULL;
  2793.     
  2794.     aStream->ReadHandle((Handle*) &ct );
  2795.     
  2796.     if ( ct && gMacInfo.supportsColour )
  2797.         SetWinColor( macWindow, ct );
  2798.             
  2799.     aStream->ReadShort( &h );
  2800.     aStream->ReadShort( &v );
  2801.     MoveWindow( macWindow, h, v, FALSE );
  2802.     
  2803.     aStream->ReadRect( &sizeRect );
  2804.     aStream->ReadShort( &windID );
  2805.     aStream->ReadChar((char*) &isNamed );
  2806.     aStream->ReadChar((char*) &stationeryFile );
  2807.     dLen = sizeof( FSSpec );
  2808.     aStream->ReadData((Ptr) &macFile, &dLen );
  2809.     aStream->ReadLong((long*) &macFType );
  2810.     aStream->ReadChar((char*) &printable );
  2811.     aStream->ReadChar((char*) &floating );
  2812.     aStream->ReadChar((char*) &disableAutoClose );
  2813.     aStream->ReadRect( &zoomSource );
  2814.     
  2815.     // set up the local stuff...
  2816.     
  2817.     short    item = CountDITL( macWindow );
  2818.     baseItems = item;
  2819.     
  2820.     FailNIL( dItemInfo = ( DItemInfoHdl ) NewHandleClear( sizeof( DItemInfo ) * item ));
  2821.  
  2822.     SetUpUserItems();            // install user item procs so we get callbacks
  2823.     SetUpRadioGroups();
  2824.     
  2825.     // read the handle which is a list of DItemInfo records- this restores group info and states,
  2826.     // though the above call is still needed to strip off control title grouping characters.
  2827.     
  2828.     DisposeHandle((Handle) dItemInfo );
  2829.     aStream->ReadHandle((Handle*) &dItemInfo );
  2830.     FailNIL( dItemInfo );
  2831.     
  2832.     aStream->ReadHandle((Handle*) &ictb );
  2833.  
  2834.     // finally, we must read the true states and values of all of the dialog items
  2835.     
  2836.     for( h = 1; h <= item; h++ )
  2837.     {
  2838.         v = GetItemType( h ) & 0x7F;
  2839.         
  2840.         switch( v )
  2841.         {
  2842.             case editText:
  2843.             case statText:
  2844.                 // text items are strings
  2845.                 aStream->ReadString( title );
  2846.                 SetValue( h, title );
  2847.                 break;
  2848.                 
  2849.             case userItem:
  2850.             case picItem:
  2851.             case iconItem:
  2852.                 // these items are currently not streamed- the correct resources must be present.
  2853.                 break;
  2854.                 
  2855.             default:
  2856.                 // controls' values are longs
  2857.                 aStream->ReadLong( &dLen );
  2858.                 SetValue( h, dLen );
  2859.                 break;
  2860.         }
  2861.     }
  2862.     
  2863.     SetUp();                    // call user's set up method
  2864.     OutlineDefaultItem();        // set default button to ok button
  2865.     
  2866.     // register with window manager...
  2867.     
  2868.     gWindowManager->AddWindow( this );
  2869.     ResetAlertStage();
  2870.     
  2871.     if ( vis )
  2872.         Show();
  2873. #endif
  2874. }
  2875.  
  2876.  
  2877. /*--------------------------***  CLEARDITLPLACEHOLDERS  ***-----------------------------*/
  2878. /*
  2879. in order to stream a dialog's item list, the place holder fields must generally be
  2880. cleared. This performs that on what is expected to be a COPY of the dialog items list.
  2881. ----------------------------------------------------------------------------------------*/
  2882.  
  2883. void    ZDialog::ClearDITLPlaceHolders( Handle ditl )
  2884. {
  2885.     FailNILParam( ditl );
  2886.     HLock( ditl );
  2887.     
  2888.     long    dl = GetHandleSize( ditl );
  2889.     long    off = 2;
  2890.     Ptr        p = *ditl;
  2891.     
  2892.     while( off <= dl )
  2893.     {
  2894.         // clear place holder:
  2895.         
  2896.         *(long*)( p + off ) = 0;    
  2897.     
  2898.         // calculate offset to next one. This is equal to 13 + the value
  2899.         // at 14 bytes from current place.
  2900.         
  2901.         off += 13;
  2902.         off += *( p + off ) + 1;
  2903.         
  2904.         // if that's an odd address, increment by one
  2905.         
  2906.         if ( off & 1 )
  2907.             off++;
  2908.     }
  2909.     
  2910.     HUnlock( ditl );
  2911. }
  2912.  
  2913.  
  2914. #pragma mark -
  2915. /*--------------------------***  UserItemVectorProc  ***--------------------------------*/
  2916. /*    
  2917.  
  2918. This is used to vector user-item updates to the DrawUserItem method. Do not change this-
  2919. override DrawUserItem instead.
  2920.  
  2921. ----------------------------------------------------------------------------------------*/
  2922.  
  2923. static pascal void    UserItemVectorProc( DialogPtr theDialog, short item )
  2924. {
  2925.     ZDialog*    aZD = (ZDialog*) GetWRefCon( theDialog );
  2926.     
  2927.     if ( aZD )
  2928.         aZD->DrawUserItem( item );
  2929. }
  2930.  
  2931.  
  2932. /*-------------------------------***  REALTOSTRING  ***---------------------------------*/
  2933.  
  2934. void RealToString( const double num, Str255& str, short decPlaces )
  2935. {
  2936.     decimal     d;
  2937.     decform        df;
  2938.     
  2939.     df.style = FIXEDDECIMAL;
  2940.     df.digits = decPlaces;
  2941.     
  2942.     num2dec( &df, num, &d );
  2943.     dec2str( &df, &d, (char*) &str[1] );
  2944.     
  2945.     // set length of pascal string by scanning until we reach null terminator
  2946.     
  2947.     str[0] = 0;
  2948.     while( str[++str[0]] );
  2949. }
  2950.  
  2951.  
  2952. /*-------------------------------***  FRAMEGRAYRECT  ***---------------------------------*/
  2953.  
  2954.  
  2955. void    FrameGrayRect( Rect* aRect )
  2956. {
  2957.     Rect        globRect;
  2958.     GDHandle    aDev;
  2959.     RGBColor    aColour;
  2960.     RGBColor    bColour;
  2961.     
  2962.     // frames a rectangle using two shades of gray so that the rectangle appears to
  2963.     // be recessed into a gray surface. This actually draws 1 pixel outside the
  2964.     // passed rectangle, so that normal FrameRect calls work as expected in addition.
  2965.     
  2966.     globRect = *aRect;
  2967.     LocalToGlobal( &topLeft( globRect ));
  2968.     LocalToGlobal( &botRight( globRect ));
  2969.     aDev = GetMaxDevice( &globRect );
  2970.     
  2971.     GetBackColor( &aColour );
  2972.     bColour.red = bColour.green = bColour.blue = 0xFFFF;
  2973.     GetGray( aDev, &aColour, &bColour );
  2974.     
  2975.     RGBForeColor( &bColour );
  2976.     MoveTo( aRect->left, aRect->bottom );
  2977.     LineTo( aRect->right, aRect->bottom );
  2978.     LineTo( aRect->right, aRect->top );
  2979.     
  2980.     bColour.red = bColour.green = bColour.blue = 0;
  2981.     GetGray( aDev, &aColour, &bColour );
  2982.     RGBForeColor( &bColour );
  2983.     
  2984.     Move( 0, -1 );
  2985.     LineTo( aRect->left - 1, aRect->top - 1 );
  2986.     LineTo( aRect->left - 1, aRect->bottom );
  2987.     
  2988.     ForeColor( blackColor );
  2989. }
  2990.  
  2991.  
  2992.  
  2993.